如何通过引用另一个批处理文件将环境变量作为参数传递? [英] How to pass environment variables as parameters by reference to another batch file?

查看:41
本文介绍了如何通过引用另一个批处理文件将环境变量作为参数传递?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个关于 Windows 批处理的问题.我有两个批处理文件/脚本,第一个调用第二个,多次使用不同的参数.

I have a question about Windows batch. I have two batch files/scripts, the first one calls the second one, several times with different parameters.

我想在第一个环境变量中创建几个环境变量并将它们作为参数传递给第二个.在第二个批处理脚本中,每个传递的变量都应增加一个在第二个批处理文件中确定的值.然后在第二个批处理文件的下一次调用时再次传递第一个批处理文件中的环境变量,并且第二个批处理文件应相应地再次增加它们的值.

I want to create several environment variables in the first one and pass them as parameters to the second one. In this second batch script the passed variables should be increased each by a value determined in the second batch file. Then the environment variables in first batch file are passed again on the next call of the second batch file and their values should be incremented once again accordingly by the second batch file.

第一个 .bat 脚本:

::Modules find
set anz_Modules=0
::Modules build successful
set SR_Modules=0
set CPP_Modules=0

call ./Pearl_p2cpp.bat EXTRA auto anz_Modules SR_Modules CPP_Modules
rem Here are more calls of Pearl_p2cpp.bat with varying first parameter.
call ./Pearl_p2cpp.bat FKT auto anz_Modules SR_Modules CPP_Modules

第二个.bat脚本Pearl_p2cpp.bat:

::Globale Variablen aus *_ALLES.bat bearbeiten
if NOT[%3]==[] goto noParams
set /a "%~3=%3%+%numberOfModuls%"

if NOT[%4]==[] goto noParams
set /a "%~4=%4%+%SRecordSuccess%"

if NOT[%5]==[] goto noParams
set /a "%~5=%5%+%CppSuccess%"

:noParams

第一个 .bat 脚本:

echo Es wurden insgesammt [%anz_Modules%]*.P (PEARL)-Module gefunden
echo aus diesen wurden [%SR_Modules%]-SREC und [%CPP_Modules%]-C++ Dateien in %TookTime:~0,-2%.%TookTime:~-2% seconds gebuildet! 

输出:

Es wurden insgesammt [0]*.P (PEARL)-Module gefunden
aus diesen wurden [0]-SREC und [0]-C++ Dateien in 143.41 seconds gebuildet!

Es wurden insgesammt [0]*.P (PEARL)-Module gefunden
aus diesen wurden [0]-SREC und [0]-C++ Dateien in 143.41 seconds gebuildet!

增加或编辑变量似乎不起作用.

Increasing, or editing the variables does not seem to work.

有什么问题?

更新 2021-04-09:

以下是根据 Mofi 在最终删除的评论中的建议,更改的批处理脚本.第二个批处理文件现在使用保存临时值的局部变量.第二个批处理文件应将 endlocal 末尾的新值与 set "%~3=%interimVAR%" 传回.

Here are the changed batch scripts according to suggestions by Mofi in finally deleted comments. The second batch file works now with local variables which save the interim values. The second batch file should pass back the new values at the end of endlocal with set "%~3=%interimVAR%".

但是输出仍然是错误的,因为输出的是第一个批处理文件的初始值.

But the output is still wrong as output are the initial values of first batch file.

完整的第一个 .bat 脚本:

@echo off

:: Store start time
set StartTIME=%TIME%
set H=%StartTIME:~0,2%
if "%H:~0,1%"==" " set H=%H:~1,1%
if "%H:~0,1%"=="0" set H=%H:~1,1%
set M=%StartTIME:~3,2%
if "%M:~0,1%"=="0" set M=%M:~1,1%
set S=%StartTIME:~6,2%
if "%S:~0,1%"=="0" set S=%S:~1,1%
set U=%StartTIME:~9,2%
if "%U:~0,1%"=="0" set U=%U:~1,1%
)
set /a Start100S=%H%*360000+%M%*6000+%S%*100+%U%

::Modules found
set /A "anz_Modules = 0"
::Modules build successful
set /A "SR_Modules = 0"
set /A "CPP_Modules = 0"

call "%~dp0Pearl_p2cpp.bat" EXTRA auto %anz_Modules% %SR_Modules% %CPP_Modules%
call cd ../.batch_scripts

call "%~dp0Pearl_p2cpp.bat" FKT auto %anz_Modules% %SR_Modules% %CPP_Modules%
call cd ../.batch_scripts

call "%~dp0Pearl_p2cpp.bat" FKTREP auto %anz_Modules% %SR_Modules% %CPP_Modules%
call cd ../.batch_scripts

call "%~dp0Pearl_p2cpp.bat" FKTZU auto %anz_Modules% %SR_Modules% %CPP_Modules%
call cd ../.batch_scripts

call "%~dp0Pearl_p2cpp.bat" KALIB auto %anz_Modules% %SR_Modules% %CPP_Modules%
call cd ../.batch_scripts

call "%~dp0Pearl_p2cpp.bat" LASER auto %anz_Modules% %SR_Modules% %CPP_Modules%
call cd ../.batch_scripts

call "%~dp0Pearl_p2cpp.bat" MOAB auto %anz_Modules% %SR_Modules% %CPP_Modules%
call cd ../.batch_scripts

call "%~dp0Pearl_p2cpp.bat" MOENDE auto %anz_Modules% %SR_Modules% %CPP_Modules%
call cd ../.batch_scripts

call "%~dp0Pearl_p2cpp.bat" MOZU auto %anz_Modules% %SR_Modules% %CPP_Modules%
call cd ../.batch_scripts

call "%~dp0Pearl_p2cpp.bat" MTERM auto %anz_Modules% %SR_Modules% %CPP_Modules%
call cd ../.batch_scripts

call "%~dp0Pearl_p2cpp.bat" MTERM\RTOS auto %anz_Modules% %SR_Modules% %CPP_Modules%
call cd ..
call cd ../.batch_scripts

call "%~dp0Pearl_p2cpp.bat" PAKZU auto %anz_Modules% %SR_Modules% %CPP_Modules%
call cd ../.batch_scripts

call "%~dp0Pearl_p2cpp.bat" PE auto %anz_Modules% %SR_Modules% %CPP_Modules%
call cd ../.batch_scripts

call "%~dp0Pearl_p2cpp.bat" SRS auto %anz_Modules% %SR_Modules% %CPP_Modules%
call cd ../.batch_scripts

call "%~dp0Pearl_p2cpp.bat" SRTBEG2 auto %anz_Modules% %SR_Modules% %CPP_Modules%
call cd ../.batch_scripts

call "%~dp0Pearl_p2cpp.bat" STDBY auto %anz_Modules% %SR_Modules% %CPP_Modules%
call cd ../.batch_scripts

call "%~dp0Pearl_p2cpp.bat" VDE auto %anz_Modules% %SR_Modules% %CPP_Modules%
call cd ../.batch_scripts

call "%~dp0Pearl_p2cpp.bat" VGL auto %anz_Modules% %SR_Modules% %CPP_Modules%
call cd ../.batch_scripts

:: Get the end time
set StopTIME=%TIME%
set H=%StopTIME:~0,2%
if "%H:~0,1%"==" " set H=%H:~1,1%
if "%H:~0,1%"=="0" set H=%H:~1,1%
set M=%StopTIME:~3,2%
if "%M:~0,1%"=="0" set M=%M:~1,1%
set S=%StopTIME:~6,2%
if "%S:~0,1%"=="0" set S=%S:~1,1%
set U=%StopTIME:~9,2%
if "%U:~0,1%"=="0" set U=%U:~1,1%
)

set /a Stop100S=%H%*360000+%M%*6000+%S%*100+%U%
:: Test midnight rollover. If so, add 1 day=8640000 1/100ths secs
if %Stop100S% LSS %Start100S% set /a Stop100S+=8640000
set /a TookTime=%Stop100S%-%Start100S%
echo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
echo ----------------------------------------------------------------------------------------------------
::echo um %StartTime% Uhr gestartet
::echo um %StopTime% Uhr beendet
echo Es wurden insgesammt [%anz_Modules%]*.P (PEARL)-Module gefunden
echo aus diesen wurden [%SR_Modules%]-SREC und [%CPP_Modules%]-C++ Dateien in %TookTime:~0,-2%.%TookTime:~-2% seconds gebuildet! 
echo ----------------------------------------------------------------------------------------------------
echo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

完整的 second.bat 脚本:

@echo off    

echo compile and port moduls in subfolder "%1"
cd .././%1
pwd
echo *.Px ,*.cpp und *.SR-Dateien werden geloescht.

if /i "%2%"=="auto" GOTO nopause_1

pause

rm *.Px
rm *.SR

echo Konvertierungen starten:

:nopause_1

if /i "%2%"=="auto" GOTO no_time_rec

  :: Store start time
  set StartTIME=%TIME%
  set H=%StartTIME:~0,2%
  if "%H:~0,1%"==" " set H=%H:~1,1%
  if "%H:~0,1%"=="0" set H=%H:~1,1%
  set M=%StartTIME:~3,2%
  if "%M:~0,1%"=="0" set M=%M:~1,1%
  set S=%StartTIME:~6,2%
  if "%S:~0,1%"=="0" set S=%S:~1,1%
  set U=%StartTIME:~9,2%
  if "%U:~0,1%"=="0" set U=%U:~1,1%
  )
  set /a Start100S=%H%*360000+%M%*6000+%S%*100+%U%

:no_time_rec

setlocal EnableDelayedExpansion

set cppExtension=".cpp"
set PearlExtension=".P"
set SRecordExtension=".SR"

set /a "SRecordSuccess=0"
set /a "CppSuccess=0"
set /a "numberOfModuls=0"
set doCompilePort=true

for /f %%a IN ('dir /b *.P') do (
  
  echo Modul %%a
  set doCompilePort=true

  if "%%a" == "INCL.P" set doCompilePort=false
  if "%%a" == "INCL_FKR.P" set doCompilePort=false
  if "%%a" == "INCL_GLO.P" set doCompilePort=false
  if "%%a" == "INCL_PE.P" set doCompilePort=false
  if "%%a" == "INCL_STB.P" set doCompilePort=false
  if "%%a" == "INCL_VDE.P" set doCompilePort=false
  
  echo doCompilePort:!doCompilePort!
  
  
  if "!doCompilePort!" == "true" (
    echo start compiler
    

    set /a numberOfModuls=!numberOfModuls!+1
    echo modul number !numberOfModuls!
    
    echo Convert
    set filename=%%a
    set fileBasename=!filename:~0,-2!
    rm !fileBasename!.cpp
    echo returnValue rm !errorlevel!
  
    set filenameSR=!fileBasename!.SR

    call C:\programme\compiler\rtos-uh\pe\pe.exe C:\programme\compiler\rtos-uh\ppc\PEARL90\vers16_6\P16Q6H.VBI -si=!filename! -co=!filenameSR! -lo=no -e0
    IF !errorlevel! NEQ 0 (
      REM do something here to address the error
      echo returnValue Pearl-Compiler !errorlevel!
    ) ELSE (
      set /a SRecordSuccess=!SRecordSuccess!+1
    )
        

    call pqprep !filename!
    echo returnValue pqprep !errorlevel!
    
    call p2cpp !filename!x
    
    IF !errorlevel! NEQ 0 (
      REM do something here to address the error
      echo returnValue Pearl-Compiler !errorlevel!
    ) ELSE (
      set /a CppSuccess=!CppSuccess!+1
    )
  )
  echo ----------------------------------------------------------------------------------------------------
)
echo ----------------------------------------------------------------------------------------------------

echo number of moduls: %numberOfModuls%
echo successfully created S-Records: %SRecordSuccess%
echo successfully created cpp-files: %CppSuccess%

IF %numberOfModuls% == %SRecordSuccess% (
  IF %numberOfModuls% == %CppSuccess% (
    echo all moduls successful
  )
)

::Globale Variablen aus *_ALLES.bat bearbeiten
if "%~3" == "" goto noParams
set /A "PassedVar3=%~3+numberOfModuls"

if "%~4" == "" goto noParams
set /A "PassedVar4=%~4+SRecordSuccess"

if "%~5" == "" goto noParams
set /A "PassedVar5=%~5+CppSuccess"

:noParams

if /i "%2%"=="auto" GOTO no_time_rec2

  :: Get the end time
  set StopTIME=%TIME%
  set H=%StopTIME:~0,2%
  if "%H:~0,1%"==" " set H=%H:~1,1%
  if "%H:~0,1%"=="0" set H=%H:~1,1%
  set M=%StopTIME:~3,2%
  if "%M:~0,1%"=="0" set M=%M:~1,1%
  set S=%StopTIME:~6,2%
  if "%S:~0,1%"=="0" set S=%S:~1,1%
  set U=%StopTIME:~9,2%
  if "%U:~0,1%"=="0" set U=%U:~1,1%
  )

  set /a Stop100S=%H%*360000+%M%*6000+%S%*100+%U%
  :: Test midnight rollover. If so, add 1 day=8640000 1/100ths secs
  if %Stop100S% LSS %Start100S% set /a Stop100S+=8640000
  set /a TookTime=%Stop100S%-%Start100S%

  echo wurden in %TookTime:~0,-2%.%TookTime:~-2% seconds uebersetzt und in PEARL-SRs compiliert
  echo ----------------------------------------------------------------------------------------------------

:no_time_rec2

echo *.Px -Dateien werden geloescht.
echo ----------------------------------------------------------------------------------------------------

if /i "%2%"=="auto" GOTO nopause_2

Pause

:nopause_2

rm *.Px
rm *.phx
rm *.INCx

rm *.incx


pwd
cd ./..
pwd

if "%~3" == "" goto noParams
endlocal & set "%~3=%PassedVar3%" "%~4=%PassedVar4%" "%~5=%PassedVar5%"

:noParams

echo Vorgang beenden

推荐答案

这里是完整的第一个批处理文件:

Here is the full first batch file rewritten:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem Get start time region independent in seconds and hundredths of a second
for /F "tokens=2 delims==" %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do set "LocalTime=%%I"
set /A Start100S=(1%LocalTime:~8,2%-100)*360000 + (1%LocalTime:~10,2%-100)*6000 + (1%LocalTime:~12,2%-100)*100 + (1%LocalTime:~15,2%-100)

rem Modules found
set "anz_Modules=0"
rem Modules build successful
set "SR_Modules=0"
set "CPP_Modules=0"

call "%~dp0Pearl_p2cpp.bat" EXTRA      auto anz_Modules SR_Modules CPP_Modules
call "%~dp0Pearl_p2cpp.bat" FKT        auto anz_Modules SR_Modules CPP_Modules
call "%~dp0Pearl_p2cpp.bat" FKTREP     auto anz_Modules SR_Modules CPP_Modules
call "%~dp0Pearl_p2cpp.bat" FKTZU      auto anz_Modules SR_Modules CPP_Modules
call "%~dp0Pearl_p2cpp.bat" KALIB      auto anz_Modules SR_Modules CPP_Modules
call "%~dp0Pearl_p2cpp.bat" LASER      auto anz_Modules SR_Modules CPP_Modules
call "%~dp0Pearl_p2cpp.bat" MOAB       auto anz_Modules SR_Modules CPP_Modules
call "%~dp0Pearl_p2cpp.bat" MOENDE     auto anz_Modules SR_Modules CPP_Modules
call "%~dp0Pearl_p2cpp.bat" MOZU       auto anz_Modules SR_Modules CPP_Modules
call "%~dp0Pearl_p2cpp.bat" MTERM      auto anz_Modules SR_Modules CPP_Modules
call "%~dp0Pearl_p2cpp.bat" MTERM\RTOS auto anz_Modules SR_Modules CPP_Modules
call "%~dp0Pearl_p2cpp.bat" PAKZU      auto anz_Modules SR_Modules CPP_Modules
call "%~dp0Pearl_p2cpp.bat" PE         auto anz_Modules SR_Modules CPP_Modules
call "%~dp0Pearl_p2cpp.bat" SRS        auto anz_Modules SR_Modules CPP_Modules
call "%~dp0Pearl_p2cpp.bat" SRTBEG2    auto anz_Modules SR_Modules CPP_Modules
call "%~dp0Pearl_p2cpp.bat" STDBY      auto anz_Modules SR_Modules CPP_Modules
call "%~dp0Pearl_p2cpp.bat" VDE        auto anz_Modules SR_Modules CPP_Modules
call "%~dp0Pearl_p2cpp.bat" VGL        auto anz_Modules SR_Modules CPP_Modules

rem Get end time region independent in seconds and hundredths of a second
for /F "tokens=2 delims==" %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do set "LocalTime=%%I"
set /A Stop100S=(1%LocalTime:~8,2%-100)*360000 + (1%LocalTime:~10,2%-100)*6000 + (1%LocalTime:~12,2%-100)*100 + (1%LocalTime:~15,2%-100)

rem Test midnight rollover. If so, add one day=8640000 1/100ths seconds
if %Stop100S% LSS %Start100S% set /A Stop100S+=8640000
set /A TookTime=Stop100S - Start100S
echo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
echo ----------------------------------------------------------------------------------------------------
echo Es wurden insgesammt [%anz_Modules%]*.P (PEARL)-Module gefunden.
echo Aus diesen wurden [%SR_Modules%]-SREC und [%CPP_Modules%]-C++ Dateien in %TookTime:~0,-2%.%TookTime:~-2% Sekunden erzeugt!
echo ----------------------------------------------------------------------------------------------------
echo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
endlocal

这个批处理文件首先用前两个命令行完整地定义了执行环境:

This batch file defines first with the first two command lines completely the execution environment:

  • 命令回显模式已关闭.
  • 已启用命令扩展.
  • 延迟环境变量扩展已禁用.

命令SETLOCAL

  • 将命令扩展的当前状态推送到堆栈上,
  • 将延迟扩展的当前状态推送到堆栈上,
  • 将当前目录的完整路径推入栈中,
  • 将指针推入堆栈中的当前环境变量列表,
  • 创建当前环境变量列表的副本并将该副本用作活动环境变量列表.

这总是由命令 SETLOCAL 完成,独立于运行时没有、一个或两个参数.

This is always done by the command SETLOCAL independent on being run with no, one or two parameters.

命令ENDLOCAL

  • 丢弃当前环境变量列表,
  • 从堆栈中弹出指向前一个环境变量列表的指针,并使这个环境变量列表再次成为活动环境变量列表,
  • 从堆栈中弹出前一个当前目录的完整限定路径,如果该目录仍然存在,则将该目录设为当前目录,
  • 从堆栈中弹出之前的延迟扩展状态,并相应地设置延迟扩展状态,
  • 从堆栈中弹出命令扩展的先前状态并相应地设置命令扩展的状态.

这也由 Windows 命令处理器 cmd.exe 隐式完成,用于在没有 ENDLOCAL 执行的批处理文件中执行的每个 SETLOCAL在退出批处理文件的处理之前显式完成.因此,许多在顶部某处使用 SETLOCAL 的批处理文件在末尾某处不包含 ENDLOCAL.

This is done also by the Windows command processor cmd.exe implicitly for each SETLOCAL executed within a batch file for which no ENDLOCAL execution was done explicitly before exiting the processing of a batch file. For that reason many batch files using SETLOCAL somewhere at top do not contain ENDLOCAL somewhere at end.

另见:

因此批处理文件在其自己的本地执行环境中运行,该环境不依赖于批处理文件之外定义的某些内容,但当前目录除外,因为从该批处理文件传递到调用的批处理文件的所有目录路径Pearl_p2cpp.bat 相对于批处理文件之外定义的当前目录.这可能不太好,但我无法评价.

So the batch file runs in its own local execution environment which does not depend on something defined outside of the batch file with the exception of the current directory because of all the directory paths passed from this batch file to the called batch file Pearl_p2cpp.bat are relative to current directory defined outside of the batch file. That is perhaps not so good, but I can´t rate that.

可以使用第三个命令行 pushd "%~dp0" 将当前目录路径推入堆栈并使批处理文件的目录成为当前目录并用作最后一个但是一行 popd 从堆栈中弹出初始当前目录的目录路径并将该目录再次设置为当前目录.

It would be possible to use as third command line pushd "%~dp0" to push the current directory path on stack and make the directory of the batch file the current directory and use as last but one line popd to pop from stack the directory path of the initial current directory and set this directory again as current directory.

接下来的两个命令行以百分之一秒的地区/国家独立获取当前本地时间并计算开始时间的值.有关说明,请参阅午夜后时间设置不正确.

The next two command lines get current local time with hundredths of a second region/country independent and calculate the value for the start time. For an explanation see Time is set incorrectly after midnight.

在算术表达式中,时间的每个两位十进制数前面都有字符 1,导致所有数字现在都是三位数字,最低值为 100.这是因为 SET 将算术表达式中以 0 开头的数字解释为八进制数而不是十进制数.89 在八进制数中无效.因此,0809 将被解释为无效的八进制数,而不是十进制数 89.避免将十进制数解释为八进制数的简单解决方案是在算术表达式的字符串中的每两位十进制数之前插入字符 1 并从每个字符中减去 100算术表达式求值时的十进制数.

Each two digit decimal number of the time is preceded in the arithmetic expression by character 1 resulting in all numbers being now three digit numbers with lowest value being 100. This is done because of SET interprets a number in an arithmetic expression starting with 0 as octal number and not as decimal number. The digits 8 and 9 are invalid in an octal number. For that reason 08 and 09 would be interpreted as invalid octal numbers instead of decimal numbers 8 and 9. The simple solution to avoid the interpretation of the decimal numbers as octal numbers is inserting before each two digit decimal number the character 1 in string of the arithmetic expression and subtracting 100 from each decimal number on evaluation of the arithmetic expression.

使用时间格式 hh:mm::ss.xx 获取开始/结束时间区域/国家依赖的更好代码是:

A better code to get start/end time region/country dependent with time format hh:mm::ss.xx would be:

rem Get start time region dependent in seconds and hundredths of a second.
set "LocalTime=%TIME%"
set "Hour=%LocalTime:~0,2%"
if "%Hour:~0,1%" == "0" (set "Hour=%Hour:~1%") else if "%Hour:~0,1%" == " " set "Hour=%Hour:~1%"
set "Minute=%LocalTime:~3,2%
if "%Minute:~0,1%" == "0" set "Minute=%Minute:~1%"
set "Second=%LocalTime:~6,2%"
if "%Second:~0,1%" == "0" set "Second=%Second:~1%"
set "HundredthOfSecond=%LocalTime:~9,2%
if "%HundredthOfSecond:~0,1%" == "0" set "HundredthOfSecond=%HundredthOfSecond:~1%"
set /A Start100S=Hour*360000 + Minute*6000 + Second*100 + HundredthOfSecond

rem Or for the end time the lines above with last line modified to:
set /A Stop100S=Hour*360000 + Minute*6000 + Second*100 + HundredthOfSecond

这里使用额外的 IF 条件避免了八进制数问题,这些条件在字符串值的第一个字符为 0(或小时值上的空格)上重新定义适当的环境变量只有第二个字符.所以算术表达式中的任何数字都没有前导 0.

The octal number problem is avoided here with additional IF conditions which redefine the appropriate environment variable on first character of string value being 0 (or a space on hour value) with just the second character. So no number in arithmetic expression has a leading 0.

请不要在算术表达式中引用环境变量,该变量是set/A 之后的字符串,带有%!.这是不必要的,而且适得其反.可以在算术表达式中仅通过名称引用环境变量,以便更轻松地使用它们,尤其是在 IF 条件块或 FOR 循环中.有一些例外,例如环境变量名称包含空格或被解释为算术表达式中的数学运算符的字符,或者仅应在算术表达式中使用环境变量的字符串值的一部分.但是一般来说,在使用好的环境变量名的算术表达式中可以只使用变量名.

Please never reference an environment variable within an arithmetic expression being the string after set /A with % or !. That is unnecessary and counterproductive. Environment variables can be referenced in an arithmetic expression by just their names to make it easier to use them especially in an IF condition block or a FOR loop. There are exceptions like the environment variable name contains a space or a character being interpreted as a mathematical operator in an arithmetic expression, or just a part of the string value of an environment variable should be used in the arithmetic expression. But in general just the variable name can be used in an arithmetic expression on using good environment variable names.

接下来的命令行定义了三个值为 0 的环境变量.通常不应使用算术表达式来定义具有数字的环境变量.环境变量始终是内存中的字符串,而不是整数.因此,与使用 set "anz_Modules=0" 的简单字符串定义相比,使用诸如 set/A "anz_Modules = 0" 之类的算术表达式定义环境变量需要更多 CPU 指令; 虽然现在没有用户注意到 CPU 速度非常快的差异.另请参阅:为什么在命令行上使用set var = text"后没有带有echo %var%"的字符串输出?

The next command lines define three environment variables with value 0. There should not be used in general an arithmetic expression to define an environment variable with a number. An environment variable is always a string in memory and never an integer. So it takes much more CPU instructions to define an environment variable with an arithmetic expression like set /A "anz_Modules = 0" in comparison to a simple string definition with set "anz_Modules=0" although no user notices ever the difference as CPUs are very fast nowadays. See also: Why is no string output with 'echo %var%' after using 'set var = text' on command line?

接下来的命令行块是对批处理文件Pearl_p2cpp.bat 的简单调用,带有完整的限定文件名.该批处理文件始终与第一个批处理文件存储在同一目录中,因此使用 %~dp0 扩展到第一个批处理文件的完整路径始终以反斜杠结尾确保(几乎总是)说明第二个批处理文件真的是独立于当前目录调用的.

The next block of command lines are simple calls of the batch file Pearl_p2cpp.bat with full qualified file name. This batch file is always stored in same directory as the first batch file and for that reason the usage of %~dp0 expanding to full path of first batch file ending always with a backslash makes sure (nearly always) that the second batch file is really called independent on which directory is the current directory.

带有命令 CD 的命令行都被删除了,因为它们在批处理文件中的 PUSHDPOPD 用法不再需要<代码>Pearl_p2cpp.bat.

The command lines with command CD are all removed as they should not be necessary anymore with the PUSHD and POPD usage in batch file Pearl_p2cpp.bat.

注意:cmd.exe 的内部命令(如 CD)上使用命令 CALL 是危险的并且至少增加了批处理文件的执行时间.Windows 命令处理器期望在 CALL 之后以冒号开头的参数字符串被解释为当前批处理文件中的标签,该文件应该像子例程一样调用,即批处理文件中的批处理文件,或者带或带路径以及不带或带文件扩展名的批处理文件的名称.所以 call cd 导致 cmd.exe 在当前目录中搜索,然后在环境变量 PATH 的所有目录中搜索带有文件的文件名称 cd(不区分大小写)并在环境变量 PATHEXT 的值中列出文件扩展名,当它真正找到这样的文件时,将通过传递参数执行该文件内部命令 CD 到此可执行文件或脚本,而不是运行内部命令来更改当前目录.

Note: Using the command CALL on an internal command of cmd.exe like CD is dangerous and at least increases the execution time of the batch file. The Windows command processor expects after CALL either an argument string starting with a colon being interpreted as a label in current batch file which should be called like a subroutine, i.e. a batch file inside a batch file, or the name of a batch file without or with path and without or with file extension. So call cd results in cmd.exe searching in current directory and next in all the directories in value of environment variable PATH for a file with file name cd (case-insensitive) and with a file extension listed in value of environment variable PATHEXT and when it really finds such a file, this file is executed with passing the arguments of internal command CD to this executable or script instead of running the internal command to change the current directory.

接下来确定停止/结束时间,并计算批处理文件执行结束时输出的最终信息的时间差.

Next the stop/end time is determined and the time difference is calculated for the final information output at end of execution of the batch file.

这里是完整的第二个批处理文件 Pearl_p2cpp.bat 重写,但没有完全测试:

Here is the full second batch file Pearl_p2cpp.bat rewritten, but not fully tested:

@echo off
echo Kompiliere und portiere Module im Unterverzeichnis: "%~1"
pushd "..\%~1" || exit /B
echo "%CD%"
echo *.Px und *.SR Dateien werden entfernt.

if /I not "%~2" == "auto" pause

if exist *.Px del /Q *.Px
if exist *.SR del /Q *.SR

if /I "%~2" == "auto" GOTO no_time_rec

rem Get start time region independent in seconds and hundredths of a second
for /F "tokens=2 delims==" %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do set "LocalTime=%%I"
set /A Start100S=(1%LocalTime:~8,2%-100)*360000 + (1%LocalTime:~10,2%-100)*6000 + (1%LocalTime:~12,2%-100)*100 + (1%LocalTime:~15,2%-100)

:no_time_rec

setlocal EnableExtensions EnableDelayedExpansion
echo Konvertierungen starten:
set "SRecordSuccess=0"
set "CppSuccess=0"
set "numberOfModules=0"

for /F "eol=| delims=" %%I in ('dir /A-D /B *.P 2^>nul') do (

    echo Modul %%I
    set "doCompilePort=true"

    if /I "%%I" == "INCL.P"     set "doCompilePort="
    if /I "%%I" == "INCL_FKR.P" set "doCompilePort="
    if /I "%%I" == "INCL_GLO.P" set "doCompilePort="
    if /I "%%I" == "INCL_PE.P"  set "doCompilePort="
    if /I "%%I" == "INCL_STB.P" set "doCompilePort="
    if /I "%%I" == "INCL_VDE.P" set "doCompilePort="

    if defined doCompilePort (
        echo doCompilePort:true
        echo start compiler

        set /A numberOfModules+=1
        echo module number !numberOfModules!

        echo Convert
        if exist "%%~nI.cpp" del /F "%%~nI.cpp"
        echo returnValue del !errorlevel!

        "C:\programme\compiler\rtos-uh\pe\pe.exe" "C:\programme\compiler\rtos-uh\ppc\PEARL90\vers16_6\P16Q6H.VBI" -si="%%I" -co="%%~nI.SR" -lo=no -e0
        if errorlevel 1 (
            rem Do something here to address the error.
            echo returnValue Pearl Compiler !errorlevel!
        ) else set /A SRecordSuccess+=1

        call pqprep %%I
        echo returnValue pqprep !errorlevel!

        call p2cpp %%Ix
        if errorlevel 1 (
            rem Do something here to address the error.
            echo returnValue p2cpp !errorlevel!
        ) else set /A CppSuccess+=1
    ) else echo doCompilePort:false

    echo ----------------------------------------------------------------------------------------------------
)
echo ----------------------------------------------------------------------------------------------------

echo number of modules: %numberOfModules%
echo successfully created S-Records: %SRecordSuccess%
echo successfully created cpp-files: %CppSuccess%

if %numberOfModules% == %SRecordSuccess% if %numberOfModules% == %CppSuccess% echo all modules successful

rem Globale Variablen aus *_ALLES.bat addieren.
if "%~3" == "" goto noParams
if "%~4" == "" goto noParams
if "%~5" == "" goto noParams

set /A numberOfModules+=%~3
set /A SRecordSuccess+=%~4
set /A CppSuccess+=%~5

:noParams
if /I "%~2" == "auto" goto no_time_rec2

rem Get end time region independent in seconds and hundredths of a second
for /F "tokens=2 delims==" %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do set "LocalTime=%%I"
set /A Stop100S=(1%LocalTime:~8,2%-100)*360000 + (1%LocalTime:~10,2%-100)*6000 + (1%LocalTime:~12,2%-100)*100 + (1%LocalTime:~15,2%-100)

rem Test midnight rollover. If so, add 1 day=8640000 1/100ths seconds
if %Stop100S% LSS %Start100S% set /A Stop100S+=8640000
set /A TookTime=Stop100S - Start100S

echo Die Dateien wurden in %TookTime:~0,-2%.%TookTime:~-2% Sekunden verarbeitet und in PEARL-SRs kompiliert.
echo ----------------------------------------------------------------------------------------------------

:no_time_rec2
echo *.Px Dateien werden entfernt.
echo ----------------------------------------------------------------------------------------------------
if /I not "%~2" == "auto" pause
if exist *.Px   del /Q *.Px
if exist *.phx  del /Q *.phx
if exist *.INCx del /Q *.INCx
if exist *.incx del /Q *.incx

if not "%~3" == "" (endlocal & set "%~3=%numberOfModules%" & set "%~4=%SRecordSuccess%" & set "%~5=%CppSuccess%") else endlocal
echo Vorgang beenden
popd

此批处理文件首先将当前目录的完整路径压入堆栈,并根据传递的第一个参数字符串将目录与当前目录的相对路径设为新的当前目录.批处理文件期望第一个传递的目录是当前目录的父目录的子目录.

This batch file pushes first the full path of current directory on stack and makes the directory according to passed first argument string with a path relative to current directory the new current directory. It is expected by the batch file that the first passed directory is a subdirectory of the parent directory of the current directory.

请阅读有关命名文件的 Microsoft 文档,路径和命名空间 用于解释将 .././ 替换为 ..\.Windows 上的目录分隔符是反斜杠 \ 而不是 Linux/Mac 上的斜杠 /.Windows 的大多数文件/文件夹参数字符串也可以与 / 一起使用,因为 Windows 文件管理在传递文件/文件夹名称之前将所有 / 替换为 \字符串到文件系统.但我知道几个用例,在这些用例中,在文件/文件夹名称字符串中使用 / 会导致意外行为...\(父目录)之后的 .\(当前目录)总是没用的.只要有父目录,父目录的当前目录就是已经用 ..\ 引用的父目录.

Please read the Microsoft documentation about Naming Files, Paths, and Namespaces for an explanation of replacing .././ by ..\. The directory separator on Windows is the backslash \ and not the slash / as on Linux/Mac. Most file/folder argument strings of Windows work also with / because of Windows file management replaces all / by \ before passing the file/folder name string to the file system. But I know several use cases on which the usage of / in a file/folder name strings results in an unexpected behavior. A .\ (current directory) after ..\ (parent directory) is always useless. The current directory of the parent directory is the parent directory referenced already with ..\ as long as there is a parent directory at all.

文件/文件夹字符串应始终包含在 " 中,以确保使用它们的命令即使在包含空格或这些字符之一时也始终有效 &()[]{}^=;!'+,`~.

File/folder strings should be always enclosed in " to make sure that they commands using them always work even on containing a space or one of these characters &()[]{}^=;!'+,`~.

命令pwd(打印工作目录)是一个Linux 命令.Windows 上的一种替代方法是 echo "%CD%" 或不安全的 echo %CD%.如果当前目录路径包含一个或多个 &,则后者的作用与仅输出当前目录路径不同.所以最好用双引号将当前目录路径括起来,参见上面的段落.没有 " 的安全替代方案是 setlocal EnableDelayedExpansion &回声!CD!&结束本地.但是在后台做了很多工作只是为了输出当前目录路径,在这种情况下没有双引号.

The command pwd (print working directory) is a Linux command. One replacement on Windows is echo "%CD%" or not safe echo %CD%. The latter does something different than just outputting the current directory path if the current directory path contains one or more &. So it is better to enclose the current directory path in double quotes, see paragraph above. A safe alternative without " would be setlocal EnableDelayedExpansion & echo !CD!& endlocal. But a lot is done in the background just to output the current directory path without double quotes in this case.

命令 rm (remove) 也是一个 Linux 命令.Windows 命令是 del(删除)文件和 rd(删除目录)目录.

The command rm (remove) is also a Linux command. The Windows command is del (delete) for files and rd (remove directory) for directories.

改进的第二个批处理文件仍然包含命令 SETLOCAL 以启用 延迟扩展.但这仅适用于 for 循环中的某些 echo 命令行.真正需要的命令行不再需要延迟的环境变量扩展.除了少数 echo 命令行之外的所有其他命令行都使用推荐的语法,因此不需要使用延迟扩展.

The improved second batch file contains still the command SETLOCAL to enable delayed expansion. But this is done only for some echo command lines in the for loop. The really needed command lines do not need anymore delayed environment variable expansion. All other command lines than a few echo command lines use the recommended syntax which makes the usage of delayed expansion not necessary.

我无法测试 FOR 循环内的任何内容,因此只能希望第二个批处理文件的这一部分按您的预期工作.

I could not test anything inside the FOR loop and so can only hope that this part of the second batch file works as expected by you.

设置在批处理文件顶部的当前目录中传递给pqprepp2cpp(批处理文件,可执行文件?)的两个文件名没有包含在" 应该这样做,因为我不知道这两个脚本或可执行文件是否支持用双引号括起来的文件名.The two rewritten batch files do that now with the exception of the two command lines with pqprep and p2cpp in comparison to the two original batch files which would fail multiple times for directory or file names with one or more space or &()^=;!'+, in file/directory names.Well, an exclamation mark in name of a *.P file to process by the FOR loop would be still a problem because of enabled delayed expansion.

The two file names passed to pqprep and p2cpp (batch files, executables?) in the current directory set at top of the batch file are not enclosed in " as it should be done because of I don't know if these two scripts or executables support file names enclosed in double quotes. The two rewritten batch files do that now with the exception of the two command lines with pqprep and p2cpp in comparison to the two original batch files which would fail multiple times for directory or file names with one or more space or &()^=;!'+, in file/directory names. Well, an exclamation mark in name of a *.P file to process by the FOR loop would be still a problem because of enabled delayed expansion.

It is necessary to pass the name of the environment variables to modify by the second batch file to the second batch file and not their current values as otherwise the second batch file would not know which environment variables to redefine in the environment variables list of the first batch file.

It is necessary to pass the name of the environment variables to modify by the second batch file to the second batch file and not their current values as otherwise the second batch file would not know which environment variables to redefine in the environment variables list of the first batch file.

I don't understand why there is the deletion of *.INCx and of *.incx files because of Windows file systems are case-insensitive. But the current directory is perhaps a network drive and the file system on the network resource is a Linux file system which is case-sensitive.

I don't understand why there is the deletion of *.INCx and of *.incx files because of Windows file systems are case-insensitive. But the current directory is perhaps a network drive and the file system on the network resource is a Linux file system which is case-sensitive.

Most important is the last IF condition command line:

Most important is the last IF condition command line:

if not "%~3" == "" (endlocal & set "%~3=%numberOfModules%" & set "%~4=%SRecordSuccess%" & set "%~5=%CppSuccess%") else endlocal

The environment variables numberOfModules, SRecordSuccess and CppSuccess are local environment variables of the second batch file. Their values have been increased some lines above by the values of the environment variables anz_Modules, SR_Modules and CPP_Modules of which names are passed to the second batch file.

The environment variables numberOfModules, SRecordSuccess and CppSuccess are local environment variables of the second batch file. Their values have been increased some lines above by the values of the environment variables anz_Modules, SR_Modules and CPP_Modules of which names are passed to the second batch file.

It is necessary now to explicitly run ENDLOCAL to restore the environment variables list of first batch file before exiting processing of the second batch file with additionally redefine the environment variables anz_Modules, SR_Modules and CPP_Modules in the environment variables list of the calling batch file. This is done by using on same line respectively in same command block starting with ( and ending with ) three times the command SET with the environment variable names passed to the batch file as arguments and the current values of the three local environment variables.

It is necessary now to explicitly run ENDLOCAL to restore the environment variables list of first batch file before exiting processing of the second batch file with additionally redefine the environment variables anz_Modules, SR_Modules and CPP_Modules in the environment variables list of the calling batch file. This is done by using on same line respectively in same command block starting with ( and ending with ) three times the command SET with the environment variable names passed to the batch file as arguments and the current values of the three local environment variables.

The Windows command processor CMD first processes the entire command line with the IF condition as described in detail by How does the Windows Command Interpreter (CMD.EXE) parse scripts? During this processing of the command line %~3 is replaced by anz_Modules and %numberOfModules%" by the current value of local environment variable numberOfModules. The same is done also for %~4, %SRecordSuccess%, %~5 and %CppSuccess%. The IF command line finally executed does not contain anymore an argument or an environment variable reference. The entire command line contains only all the referenced strings. For that reason the three environment variables of the calling batch file are redefined with the three values of the local environment variables which do not exist anymore after execution of the command ENDLOCAL in either true or in false branch of the IF condition.

The Windows command processor CMD first processes the entire command line with the IF condition as described in detail by How does the Windows Command Interpreter (CMD.EXE) parse scripts? During this processing of the command line %~3 is replaced by anz_Modules and %numberOfModules%" by the current value of local environment variable numberOfModules. The same is done also for %~4, %SRecordSuccess%, %~5 and %CppSuccess%. The IF command line finally executed does not contain anymore an argument or an environment variable reference. The entire command line contains only all the referenced strings. For that reason the three environment variables of the calling batch file are redefined with the three values of the local environment variables which do not exist anymore after execution of the command ENDLOCAL in either true or in false branch of the IF condition.

The last IF condition could be written also as:

The last IF condition could be written also as:

if not "%~3" == "" (
    endlocal
    set "%~3=%numberOfModules%"
    set "%~4=%SRecordSuccess%"
    set "%~5=%CppSuccess%"
) else endlocal

The result would be the same as the Windows command processor parses the entire block and replaces all argument and environment variable references by their string values before execution of the command IF.

The result would be the same as the Windows command processor parses the entire block and replaces all argument and environment variable references by their string values before execution of the command IF.

Last the second batch file restores the initial current directory which makes the usage of command CD in the first batch file unnecessary.

Last the second batch file restores the initial current directory which makes the usage of command CD in the first batch file unnecessary.

For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

  • call/?
  • cmd/?
  • del/?
  • dir/?
  • echo/?
  • endlocal/?
  • for/?
  • goto/?
  • if/?
  • pause/?
  • popd/?
  • pushd/?
  • set/?
  • setlocal/?
  • wmic/?
  • wmic os/?
  • wmic os get/?

See also single line with multiple commands using Windows batch file for an explanation of the operators & and ||.

See also single line with multiple commands using Windows batch file for an explanation of the operators & and ||.

Read the Microsoft documentation about Using command redirection operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line in a separate command process started in background with %ComSpec%/c and the command line within ' appended as additional arguments.

Read the Microsoft documentation about Using command redirection operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line in a separate command process started in background with %ComSpec% /c and the command line within ' appended as additional arguments.

这篇关于如何通过引用另一个批处理文件将环境变量作为参数传递?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆