I'm fairly new to batch scripting, however, I've done a bit of bash scripting before. My batch file will be running another program (namely phpunit) and this program will output some stuff to the command prompt. How would I go about getting the batch script to intercept this stuff that's been output and make decisions based off of it. For example, phpunit will normally print a '.' for each test which runs successfully and an 'F' for each test which fails. How how would I get the batch script to catch this output and do something different based on whether it saw a '.' or an 'F'?
3 Answers
I'll start by not answering your actual question, but these suggestions may be useful for whatever the underlying problem is you are trying to solve:
- You can have phpunit log results in a way that is easier for a machine to read.
- PHP is a valid alternative to BASH for writing commandline scripts. I use BASH for simple stuff, but once it gets beyond a couple of lines, or when I want to add loops, if statements, etc. I decide to do it properly in PHP. Other people might reach for perl or python.
In your particular case I would do it in PHP, not BASH, because it may end up needing some complicated parsing. But let's see how to do something simple in BASH. The challenge is the output might look like this:
PHPUnit 3.4.5 by Sebastian Bergmann.
......................................
Time: 10 seconds, Memory: 9.00Mb
OK (38 tests, 660 assertions)
Or might look like this:
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.
Or might look like this:
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.
I'm going to guess your application is something like an hourly cron job to run all your tests and make sure nothing has broken. So I'm just going to use a regex to hunt for the word "FAILURES":
#!/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
I'm using backticks to capture output. Some BASH experts will tell you to use $()
instead. Either way works here:
....
RESULT=$(phpunit tests/myTest.php)
...

- 1
- 1

- 27,837
- 13
- 117
- 217
In case anyone else happens to be looking for the same solution, it can be achieved by something like:
setlocal
someprog.exe > temp.txt
set /p PROGOUTPUT= < temp.txt
del temp.txt
REM do something with %PROGOUTPUT% here
endlocal
Hopefully this helps.
EDIT: I would also like the note, that while you can use the method above, I did end up using PHP to do this similar to what Darren Cook suggested below.

- 11,736
- 20
- 78
- 137
-
Is there a difference from what you do there to using backslashes, as I showed in my example? I thought getting the output was the trivial part, and the "do something" in your above code snippet is the real challenge! – Darren Cook Aug 02 '12 at 00:54
-
Yes, the "do something" part was definitely the harder part which is what led me to use something like "exec('phpunit sometest', $output)" in PHP instead of bash. – golmschenk Aug 02 '12 at 03:21
One note about your solution: if someprog.exe
generates an empty output (either nothing or just an empty line), the SET/ P
statement will not change the value of PROGOUTPUT
, meaning the variable will retain its previous value, if there was any. So, if that piece of code may be run multiple times per single execution of the script, you'll probably need to make sure that the obtained output is related to the most recent invocation of someprog
rather than a previous one.
Other than that, your code is fine, but you could do without a temporary file with the help of a FOR /F
loop:
SETLOCAL
SET PROGOUTPUT=
FOR /F "delims=" %%L IN ('someprog.exe') DO SET "PROGOUTPUT=%%L"
REM do something with %PROGOUTPUT% here
ENDLOCAL
Note that this assumes the program produces no more than a single line of output.
The "delims="
parameter tells the loop command to disregard any delimiters and treat entire lines as single values. The %%L
is the loop variable, and the body of the loop consists of just one command in this case, the one that follows DO
. If you want to add more commands, enclose the body in parentheses. You can separate commands with &
if you put them on the same line, or you could split the body into multiple lines, like this:
FOR /F "delims=" %%L IN ('someprog.exe') DO (
SET "PROGOUTPUT=%%L"
do something else
)
There's also a completely different approach if your program can be taught to return an exit code. If it can, use 0
for a successful return and a non-zero code to indicate a failure of any kind. In that case your batch script might look like this:
someprog.exe && (
do something in case of "success" (one or more commands)
) || (
do something in case of "failure" (one or more commands)
)
And you might still want to generate an output as a visual indication of the result (could be useful when running the program separately from the batch script). To hide the output when running in the batch script, just redirect it to NUL
:
someprog.exe > NUL && (
...

- 76,112
- 17
- 94
- 154