Compare output in shell

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.

links

social