我正在寻找一种从start-command启动的批处理脚本中获取值的方法。让我解释一下:
我需要通过从主批处理脚本同时启动多个子批处理脚本来利用多处理,然后在它们完成时检索每个子批处理文件的返回值。
我一直在使用带有call-command的返回变量,dbenham很好地解释了这一点。 该解决方案不允许多线程,因为子批处理脚本是一个接一个地运行的。
使用start-command允许多个正在运行的批处理脚本,但是值不会返回到我的主脚本,因为显然start-command会创建一个全新的变量上下文。
是否有人有解决方案/解决方法将值从子脚本返回到主脚本?
以下是我需要的模型:
mainScript.bat
@echo off
setlocal
set "retval1=0"
set "retval2=0"
REM run two scripts in parallel:
start "" subscript1.bat arg1 retval1
start "" subscript2.bat arg1 retval2
REM wait for returned value
:waiting
call :sleep 1
set /a "DONE=1"
if %retval1% equ 0 set "DONE=0"
if %retval2% equ 0 set "DONE=0"
if %DONE% equ 0 goto :waiting
echo returned values are %retval1% %retval2%
exit /b
subscript1.bat
@echo off
setlocal
set "arg1=%~1"
set "retval1=%~1"
REM do some stuff...
REM return value
(endlocal
set "%retval1%=%foo%"
)
exit /b
答案 0 :(得分:2)
看不到将返回值写入文件的替代方法,所以
主要强>
@ECHO OFF
SETLOCAL
for %%a in (1 2) do (
del "%temp%\retval%%a" 2>nul
)
start /min "" q225220791.bat arg1 retval1
choice /t 1 /d y >nul
start /min "" q225220791.bat arg1 retval2
:waiting
choice /t 1 /d y >nul
ECHO wait...%retval1%...%retval2%
if not exist "%temp%\retval1" goto waiting
if not exist "%temp%\retval2" goto waiting
for %%a in (1 2) do (
for /f "usebackqdelims=" %%i in ("%temp%\retval%%a") do set "retval%%a=%%i"
)
for %%a in (1 2) do (
del "%temp%\retval%%a" 2>nul
)
echo returned values are %retval1% %retval2%
GOTO :EOF
<强> q225220791.bat 强>
@ECHO OFF
SETLOCAL
:: wait a random time 2..10 sec.
SET /a timeout=%RANDOM% %% 8 + 2
choice /t %timeout% /d y >nul
:: return a random result 12..20
SET /a foo=%RANDOM% %% 8 + 12
>"%temp%\%2" echo %foo%
ENDLOCAL
exit
依靠第二个参数的值给子进程设置临时文件名。我已经改变了批次的名称以适应我的系统。
答案 1 :(得分:0)
不确定这是否实用,只是测试以避免临时文件。因此,在子进程中查找可以从父进程中获取的位置,我决定使用窗口标题。
<强> task.cmd 强>
@echo off
setlocal
rem Retrieve task information and set window title
set "taskID=%~1"
title [task];%taskID%;working;
rem Retrieve the rest of parameters. For this sample, a random value
set /a "timeToWait=%~2 %% 30"
rem Simulate command processing
timeout /t %timeToWait%
rem Calculate a return value for this task
for /f "tokens=1-10 delims=,.:/ " %%a in ("%date%%time%_%~2") do set "returnValue=%%a%%b%%c%%d%%e%%f%%g%%h%%i%%j"
rem Signal the end of the task
title [task];%taskID%;ended; my return value is %returnValue% ;
rem Wait for master to end this tasks
cls
echo Waiting for master....
waitfor %taskID%
rem Cleanup
endlocal
<强> master.cmd 强>
@echo off
setlocal enableextensions enabledelayedexpansion
rem Configure tasks
set "taskPrefix=myTSK"
set "numTasks=5"
rem Start tasks
for /l %%a in (1 1 %numTasks%) do (
set "return[%taskPrefix%%%a]=unknown"
start "[task];%taskPrefix%%%a;working;" cmd /c "task.cmd %taskPrefix%%%a !random!"
)
rem Wait for tasks to start
timeout /t 2 > nul
rem Wait for tasks to end. Get the list of cmd.exe windows with window title
rem to see the state of the task
rem Tasks in working state indicate master needs to keep working
rem Tasks in ended state have the return value in the window title and are
rem waiting for the master to retrieve the value and end them
:wait
set "keepWaiting="
for /f "tokens=9 delims=," %%a in ('tasklist /fi "imagename eq cmd.exe" /fo csv /v ^| findstr /l /c:"[task];%taskPrefix%"'
) do for /f "tokens=2-4 delims=;" %%b in ("%%a") do (
if "%%c"=="working" (
set "keepWaiting=1"
) else if "%%c"=="ended" (
set "return[%%b]=%%d"
start "" /min waitfor.exe /si %%b
)
)
rem If any task has been found in working state, keep waiting
if defined keepWaiting (
echo %time% : waiting ...
timeout /t 5 > nul
goto wait
)
rem All tasks have ended. Show return values
for /l %%a in (1 1 %numTasks%) do (
echo task #%%a ended with exit value :[!return[%taskPrefix%%%a]!]
)
endlocal
在此示例中,任务使用waitfor
命令等待master。在XP中,这是不可用的,可以只用暂停替换,并且从master.cmd
必须修改等待循环以在tasklist
处理中包含processID令牌,因此可以关闭等待任务与taskkill
。