如何将命令的输出重定向到 diff

sta*_*wer 1 testing bash diff

我正在尝试编写一个循环,但这不起作用:

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
Run Code Online (Sandbox Code Playgroud)

这也没有帮助:

$parser_test `cat $t` | $DIFF $t.out -
Run Code Online (Sandbox Code Playgroud)

Diff 显示输出不同(很奇怪,我看到所需错误行的输出,因为它被打印到 stdout,并且没有被 diff 捕获),但是当使用临时文件运行时,一切正常:

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
Run Code Online (Sandbox Code Playgroud)

我必须避免使用临时文件。为什么第一个循环不起作用以及如何修复它?谢谢。

PS 文件 *.in 包含程序的错误命令行参数,而 *.out 包含程序必须为这些参数打印的错误消息。

Sir*_*hos 5

首先,对于您的错误,您需要重定向标准错误:

diff $t.out <($parser_test `cat $t` 2>&1)
Run Code Online (Sandbox Code Playgroud)

其次,对于您可能不知道的所有其他问题:

  • 不要lsfor循环一起使用(它有很多问题,例如包含空格的文件名中的意外行为);相反,使用:for t in $TESTS_PATH1/cmd*.in; do
  • 要支持带空格的文件名,请引用变量扩展:"$t"而不是$t
  • 不要使用反引号;它们已被弃用,取而代之的是$(command)
  • 不要使用子 shell 来捕获一个文件;相反,只需运行:$parser_test <$t
  • 使用[[ $? == 0 ]](新语法)或[ $? -eq 0 ](旧语法)
  • 如果您使用printf而不是echo,请不要忘记您需要添加\n在行尾手动添加
  • 从不使用1> $TMP_FILE 2> $TMP_FILE- 这只是以不可预测的方式用 stderr 覆盖 stdout 。如果您想组合标准输出和标准错误,请使用:1>$TMP_FILE 2>&1
  • 按照惯例,ALL_CAPS 名称用于/由环境变量使用。脚本内变量名称建议为 no_caps。
  • 你不需要$?在执行命令后立即使用,这是多余的。相反,您可以直接运行:if command; then ...

解决所有问题后,您的脚本将如下所示:

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
Run Code Online (Sandbox Code Playgroud)

如果您不关心 diff 的实际输出,您可以>/dev/null在后面添加diff以使其静音。

第三,如果我理解正确,您的文件名的形式为foo.infoo.out,而不是foo.infoo.in.out(如上面的脚本所期望的)。如果这是真的,您需要将该diff行更改为:

diff "${t/.in}.out" <($parser_test <"$t" 2>&1)
Run Code Online (Sandbox Code Playgroud)