我对批处理脚本相当陌生,但是,我以前做过一些 bash 脚本。我的批处理文件将运行另一个程序(即 phpunit),该程序将向命令提示符输出一些内容。我将如何让批处理脚本拦截这些已输出的内容并根据它做出决策。例如,phpunit 通常会打印一个 '.' 成功运行的每个测试和失败的每个测试的“F”。我如何让批处理脚本捕捉这个输出并根据它是否看到'。'做一些不同的事情 还是“F”?
3 回答
我将首先不回答您的实际问题,但这些建议可能对您要解决的任何潜在问题有用:
- 您可以以一种更易于机器阅读的方式获取 phpunit 日志结果。
- PHP 是用于编写命令行脚本的 BASH 的有效替代方案。我将 BASH 用于简单的东西,但是一旦它超出了几行,或者当我想添加循环、if 语句等时,我决定在 PHP 中正确地完成它。其他人可能会使用 perl 或 python。
在你的特殊情况下,我会用 PHP,而不是 BASH,因为它最终可能需要一些复杂的解析。但是让我们看看如何在 BASH 中做一些简单的事情。挑战在于输出可能如下所示:
PHPUnit 3.4.5 by Sebastian Bergmann.
......................................
Time: 10 seconds, Memory: 9.00Mb
OK (38 tests, 660 assertions)
或者可能看起来像这样:
PHPUnit 3.4.5 by Sebastian Bergmann.
............................................................ 60 / 380
............................................................ 120 / 380
...............................................S............ 180 / 380
.......S.................................................... 240 / 380
............................................................ 300 / 380
............................................................ 360 / 380
....................
Time: 01:44, Memory: 14.50Mb
OK, but incomplete or skipped tests!
Tests: 380, Assertions: 6546, Skipped: 2.
或者可能看起来像这样:
PHPUnit 3.4.5 by Sebastian Bergmann.
..IF
Time: 0 seconds, Memory: 8.00Mb
There was 1 failure:
1) MyTest::testTemp
Failed asserting that <boolean:false> is true.
/path/to/myTest.php:68
FAILURES!
Tests: 4, Assertions: 5, Failures: 1, Incomplete: 1.
我猜你的应用程序就像一个每小时一次的 cron 工作来运行你的所有测试并确保没有任何问题。所以我将使用正则表达式来寻找“失败”这个词:
#!/bin/bash
RESULT=`phpunit tests/myTest.php`
if [[ $RESULT =~ FAILURES ]]
then
echo "Excuse me, Sir, but we have a problem in the unit tests...";echo "$RESULT"
fi
我正在使用反引号来捕获输出。一些 BASH 专家会告诉你$()
改用。无论哪种方式都在这里工作:
....
RESULT=$(phpunit tests/myTest.php)
...
如果其他人碰巧正在寻找相同的解决方案,可以通过以下方式实现:
setlocal
someprog.exe > temp.txt
set /p PROGOUTPUT= < temp.txt
del temp.txt
REM do something with %PROGOUTPUT% here
endlocal
希望这会有所帮助。
编辑:我还想注意,虽然您可以使用上面的方法,但我最终还是使用 PHP 来执行此操作,类似于下面 Darren Cook 的建议。
关于您的解决方案的一个注意事项:如果someprog.exe
生成一个空输出(什么都没有或只是一个空行),则该SET/ P
语句不会更改 的值PROGOUTPUT
,这意味着该变量将保留其先前的值(如果有的话)。因此,如果该段代码可能在每次执行脚本时运行多次,您可能需要确保获得的输出与最近的调用相关,someprog
而不是与之前的调用相关。
除此之外,您的代码很好,但是您可以在FOR /F
循环的帮助下不使用临时文件:
SETLOCAL
SET PROGOUTPUT=
FOR /F "delims=" %%L IN ('someprog.exe') DO SET "PROGOUTPUT=%%L"
REM do something with %PROGOUTPUT% here
ENDLOCAL
请注意,这假设程序只产生一行输出。
该"delims="
参数告诉循环命令忽略任何分隔符并将整行视为单个值。是循环变量,在这种%%L
情况下,循环体只包含一个命令,即后面的命令DO
。如果要添加更多命令,请将正文括在括号中。如果将命令&
放在同一行,则可以将它们分开,也可以将正文分成多行,如下所示:
FOR /F "delims=" %%L IN ('someprog.exe') DO (
SET "PROGOUTPUT=%%L"
do something else
)
如果您的程序可以被教导返回退出代码,那么还有一种完全不同的方法。如果可以,请使用0
成功返回和非零代码来指示任何类型的失败。在这种情况下,您的批处理脚本可能如下所示:
someprog.exe && (
do something in case of "success" (one or more commands)
) || (
do something in case of "failure" (one or more commands)
)
而且您可能仍希望生成一个输出作为结果的视觉指示(在将程序与批处理脚本分开运行时可能很有用)。要在批处理脚本中运行时隐藏输出,只需将其重定向到NUL
:
someprog.exe > NUL && (
...