1

I am trying to write a loop, and this doesn't work:

for t in `ls $TESTS_PATH1/cmd*.in` ; do
  diff $t.out <($parser_test `cat $t`)
  # Print result
  if [[ $? -eq 0 ]] ; then
    printf "$t ** TEST PASSED **"
  else
    printf "$t ** TEST FAILED **"
  fi
done

This also doesn't help:

$parser_test `cat $t` | $DIFF $t.out -

Diff shows that output differs (it's strange, I see output of needed error line as it was printed to stdout, and not caught by diff), but when running with temporary file, everything works fine:

for t in `ls $TESTS_PATH1/cmd*.in` ; do
  # Compare output with template
  $parser_test `cat $t` 1> $TMP_FILE 2> $TMP_FILE
  diff $TMP_FILE $t.out
  # Print result
  if [[ $? -eq 0 ]] ; then
      printf "$t $CGREEN** TEST PASSED **$CBLACK"
  else
      printf "$t $CRED** TEST FAILED **$CBLACK"
  fi
done

I must avoid using temporary file. Why first loop doesn't work and how to fix it? Thank you.

P.S. Files *.in contain erroneous command line parameters for program, and *.out contain errors messages that program must print for these parameters.

1

2 Answers 2

5

First, to your error, you need to redirect standard error:

diff $t.out <($parser_test `cat $t` 2>&1)

Second, to all the other problems you may not be aware of:

  • don't use ls with a for loop (it has numerous problems, such as unexpected behavior in filenames containing spaces); instead, use: for t in $TESTS_PATH1/cmd*.in; do
  • to support file names with spaces, quote your variable expansion: "$t" instead of $t
  • don't use backquotes; they are deprecated in favor of $(command)
  • don't use a subshell to cat one file; instead, just run: $parser_test <$t
  • use either [[ $? == 0 ]] (new syntax) or [ $? -eq 0 ] (old syntax)
  • if you use printf instead of echo, don't forget that you need to add \n at the end of the line manually
  • never use 1> $TMP_FILE 2> $TMP_FILE - this just overwrites stdout with stderr in a non-predictable manner. If you want to combine standard out and standard error, use: 1>$TMP_FILE 2>&1
  • by convention, ALL_CAPS names are used for/by environment variables. In-script variable names are recommended to be no_caps.
  • you don't need to use $? right after executing a command, it's redundant. Instead, you can directly run: if command; then ...

After fixing all that, your script would look like this:

for t in $tests_path1/cmd*.in; do
    if diff "$t.out" <($parser_test <"$t" 2>&1); then
        echo "$t ** TEST PASSED **"
    else
        echo "$t ** TEST FAILED **"
    fi
done

If you don't care for the actual output of diff, you can add >/dev/null right after diff to silence it.

Third, if I understand correctly, your file names are of the form foo.in and foo.out, and not foo.in and foo.in.out (like the script above expects). If this is true, you need to change the diff line to this:

diff "${t/.in}.out" <($parser_test <"$t" 2>&1)
Sign up to request clarification or add additional context in comments.

Comments

2

In your second test you are capturing standard error, but in the first one (and the pipe example) stderr remains uncaptured, and perhaps that's the "diff" (pun intended).

You can probably add a '2>&1' in the proper place to combine the stderr and stdout streams.

.eg.

diff $t.out <($parser_test cat $t 2>&1)

Not to mention, you don't say what "doesn't work" means, does that mean it doesn't find a difference, or it exits with an error message? Please clarify in case you need more info.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.