通过start命令返回变量

时间:2014-03-20 02:10:03

标签: windows multithreading batch-file scope

我正在寻找一种从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

2 个答案:

答案 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