Compare output in shell
We need to compare output when we want to test command line programs. There are tools for this like Bats[1], Cram[2] or Aruba[3], but you can also roll your own. All that you need is to check if output of programs is what you expect and a test runner. The tests themselves can just be executable scripts that follow some convention for the messages they emit to the console.
If you want to do it in pure shell, the following approach seems like a good idea: If necessary, massage the result of a program with sed (for example, replace dates with a keyword like DATE, so your test does not depend on the clock of the computer), then compare with diff.
Note
|
Most people do know diff as a file compare tool, but you can compare strings with it, using process substitution: diff <(echo "$string1" ) <(echo "$string2") |
Here’s a simple example:
$ test1=$(cat << EOF > One line > Second line > Third line > EOF > ) $ echo $test1 One line Second line Third line $ echo "$test1" One line Second line Third line $ test2=$(cat << EOF One line Second line Thirde line EOF ) $ diff <(echo "$test1") <(echo "$test2") 3c3 < Third line --- > Thirde line
Note that the first time we echo the variable, all lines of the variable are displayed on one line at the prompt, although the string is still multiline and can be diffed line by line, just as expected. The variable is just displayed differently when we omit the quotes. Ah, the intricacies of Shell quoting.
Sed substitions on multiline variables also work. See here:
$ sed 's/Second line/Zweite Zeile/g' <(echo "$test1") One line Zweite Zeile Third line
Finally, as proof of concept, show that we can replace a date:
$ test1=$(cat << EOF One line 12:42 Third line EOF ) $ sed 's/[0-9][0-9]:[0-9][0-9]/DATE/g' <(echo "$test1") One line DATE Third line
To make a real test from this, make your test script write output that conforms to the TAP protocol. The basic idea is to write ok if a test succeeds and not ok if it fails. The homepage[4] of the project describes the format in detail.
To run your tests, you can use the prove test runner[5] for TAP. There are others, but I’m happy with this one so far.
To give credit where it is due: Those ideas are not entirely mine, the Git tests[6] use similar methods to massage output for testing.
BTW: The Git tests use the TAP protocol, too. So, I’m not the only fan of TAP.