Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
526 views
in Technique[技术] by (71.8m points)

windows - How to pass environment variables as parameters by reference to another batch file?

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.

First .bat script:

::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

Second.bat script 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

First .bat script again:

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! 

Output:

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.

What is the problem?

UPDATE 2021-04-09:

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.

Full first .bat script:

@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" MTERMRTOS 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 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Full second.bat script full:

@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:programmecompiler
tos-uhpepe.exe C:programmecompiler
tos-uhppcPEARL90vers16_6P16Q6H.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
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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%System32wbemwmic.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" MTERMRTOS 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%System32wbemwmic.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:

  • The command echo mode is turned off.
  • The command extensions are enabled.
  • The delayed environment variable expansion is disabled.

The command SETLOCAL

  • pushes the current status of command extensions on stack,
  • pushes the current status of delayed expansion on stack,
  • pushes the full qualified path of the current directory on stack,
  • pushes the pointer to the current environment variables list on stack,
  • creates a copy of the current environment variables list and uses that copy as active environment variables list.

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

The command ENDLOCAL

  • discards the current environment variables list,
  • pops the pointer to the previous environment variables list from stack and makes this environment variables list again the active environment variables list,
  • pops the full qualified path of the previous current directory from stack and makes this directory the current directory if still existing,
  • pops the previous status of delayed expansion from stack and sets status of delayed expansion accordingly,
  • pops the previous status of command extensions from stack and sets status of command extensions accordingly.

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.

See also:

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.

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.

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.

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

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.

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.

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?

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.

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.

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 P


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...