【问题标题】:Return variable through start command通过 start 命令返回变量
【发布时间】:2014-03-20 02:10:02
【问题描述】:

我正在寻找一种从启动命令启动的批处理脚本中获取值返回的方法。让我解释一下:

我需要通过从一个主批处理脚本同时启动多个子批处理脚本来利用多处理,然后在它们完成后检索每个子批处理文件返回值。

dbenham 很好地解释了我一直在使用带有调用命令的返回变量。 该解决方案不允许多线程,因为子批处理脚本一个接一个地运行。

使用 start-command 允许多个运行批处理脚本,但值不会返回到我的主脚本,因为 start-command 显然创建了一个全新的变量上下文。

是否有人有解决方案/解决方法将子脚本中的值返回到主脚本?

下面是我需要的模型:

ma​​inScript.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

【问题讨论】:

    标签: windows multithreading batch-file scope


    【解决方案1】:

    看不到将返回值写入文件的任何替代方法,所以

    主要

    @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,我正在写同样的答案:) 除了我会使用 SET /P 而不是 FOR /F 来读取临时文件。
    • (对不起,我来不及编辑我的第一条评论)非常感谢你们两位,FOR /F 和 SET /P 都能完美运行!出于好奇,这些之间有什么区别?据我了解,即使传递和解析多个变量,两者都会产生相同的结果。 (对于 FOR 一行,对于 SET,每行一个变量)
    • for/f 方法更通用;它更冗长,但允许处理多个输入行。 set/p 更紧凑,但必须经过哄骗才能允许输入多个。在当前情况下,没有实际区别,因为您只处理一行。番茄/番茄。选择或风格的问题。
    【解决方案2】:

    不确定这是否实用,但只是测试以避免临时文件。因此,在子进程中寻找可以从父进程读取的位置,我决定使用窗口标题。

    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
    

    ma​​ster.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 命令等待主控。在 XP 中这是不可用的,可以用暂停来代替,并且从 master.cmd 开始,必须修改等待循环以在 tasklist 处理中包含 processID 令牌,因此可以用 taskkill 关闭等待任务.

    【讨论】:

      猜你喜欢
      • 2013-09-15
      • 2019-09-03
      • 1970-01-01
      • 2018-11-18
      • 2018-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多