我试图将从程序输出的行输出到另一个脚本,这个脚本可以实时读取行,并根据行中的内容做些什么。
所以例如输出是
$program.exe Program Started Processing info Work Set Started Work Set Ended Results are.. Ending Program
我想把它传递给一个脚本,当上述程序输出“Work Set Started”时,可以触发另一个程序
我在我的trigger.bat中尝试过以下内容
@echo off SETLOCAL FOR /F "tokens=1* delims=]" %%A IN ('FIND /N /V ""') DO ( IF "%%B" == "Work Set Started" ( ProgramB.exe ) ) ENDLOCAL
当我运行以下
$program.exe | trigger.bat
ProgramB.exe不是实时启动,但是从trigger.bat收集pipe道的所有输出后执行for循环。
难道我做错了什么? 我必须使用PowerShell吗?
FOR /F
命令首先收集执行命令的所有输出,并开始处理每个输出行,直到命令结束。
你可以这样修改你的trigger.bat
文件代码:
@echo off SETLOCAL :nextLine set /P "line=" echo Line received: "%line%" FOR /F "tokens=1* delims=]" %%A IN ("%line%") DO ( IF "%%B" == "Work Set Started" ECHO ProgramB.exe IF "%%B" neq "Ending Program" GOTO NextLine )
但是,如果$program.exe
的输出速度过快,可能会出现一些同步问题。 我使用这个output.txt
文件测试了这个代码:
[1]$program.exe [2]Program Started [3]Processing info [4]Work Set Started [5]Work Set Ended [6]Results are.. [7]Ending Program
如果我只是这样做: type output.txt | trigger.bat
type output.txt | trigger.bat
程序失败,但是如果输出行通过这个output.bat
程序慢慢产生:
@echo off setlocal EnableDelayedExpansion for /F "delims=" %%a in (output.txt) do ( set /A "rand=!random! %% 4 + 2" ping -n !rand! localhost > NUL echo %%a )
…然后该方法正常工作:
C:\> output.bat | trigger.bat Line received: "[1]$program.exe " Line received: "[2]Program Started" Line received: "[3]Processing info" Line received: "[4]Work Set Started" ProgramB.exe Line received: "[5]Work Set Ended" Line received: "[6]Results are.." Line received: "[7]Ending Program"
所以你需要测试你的具体情况这个方法…
用一个简单的代码来测试生成输出
@echo off setlocal enableextensions disabledelayedexpansion >"programOutput.txt" ( echo(Program Started echo(Processing info echo(Work Set Started echo(Work Set Ended echo(Results are.. echo(Ending Program ) set program=findstr "^" programOutput.txt %program% | trigger.cmd
trigger.cmd
代码可能是类似的
@echo off setlocal enableextensions disabledelayedexpansion if "%~1"==".monitor." ( call :monitor ) else ( call :start ) goto :eof :start echo .... Entering monitor for %%t in ("%temp%\%~n0.%random%%random%%random%%random%%random%.tmp") do ( type nul >"%%~ft" findstr "^" > "%%~ft" | ( <"%%~ft" "%~f0" .monitor. & echo Start program B here ) ) & 2>nul del /q "%%~ft" echo .... Main program ended - Leaving monitor goto :eof :monitor rem Try to read data. In case of failure wait and repeat set /p "data=" || ( >nul ping -n 2 "" goto :monitor ) echo(.... monitor has retrieved [%data%] if /i "%data%"=="Work Set Started" ( echo(.... !!! : detected work set start. Leaving monitor goto :eof ) rem No end of monitoring condition found. Try again goto :monitor
正如Aacini所表明的,
for /f
的问题是在开始处理之前必须检索所有的数据。 set /p
的循环的问题是管道两侧同步。 但是这个问题有一个解决方法。 您可以使用中间文件。 也就是说,您可以将命令的输出重定向到一个文件,并且在程序写入的同时,您可以从该文件读取数据。 不是防弹,但更稳定。
处理它的一个更安全的方法是使用某种方式来指示每行开始的地方。 这是另一个trigger.cmd
替代方案,它使用find /n
命令来处理监视循环中正在处理的程序的输出。 如果输入缓冲区中的第一个字符是[
我们将假设我们已经找到了一行的开始,否则它是一个连续的行。
@echo off setlocal enableextensions disabledelayedexpansion if "%~1"==".monitor." ( call :monitor ) else ( call :start ) goto :eof :start echo .... Entering monitor set "buffer=" for %%t in ("%temp%\%~n0.%random%%random%%random%%random%%random%.tmp") do ( type nul >"%%~ft" find /n /v "" > "%%~ft" | ( <"%%~ft" "%~f0" .monitor. & echo Start program B here ) ) & 2>nul del /q "%%~ft" echo .... Main program ended - Leaving monitor goto :eof :monitor rem Try to read data. In case of failure wait and repeat set /p "data=" || ( >nul ping -n 2 "" goto :monitor ) echo(.... monitor has retrieved [%data%] rem The output of the process is being numerated by find /n rem so each line is in the form [9]xxxxxxx if not "%data:~0,1%"=="[" ( rem If we don not have a line start, append to previous buffer set "buffer=%buffer%%data%" ) else ( rem New line found to process set "buffer=%data%" ) rem Remove initial [number] data for /f "tokens=2 delims=]" %%a in ("%buffer%") do ( echo(.... checking program output [%%a] if /i "%%a"=="Work Set Started" ( echo(.... !!! detected work set start. Leaving monitor goto :eof ) ) rem No end of monitoring condition found. Try again goto :monitor
注意 :虽然在写代码的时候还没有意识到,但我重复了(而不是最好的)dbenham的工作。 请参阅这篇文章 ,以获得相同想法的改进版本。