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

时间:2013-05-13 14:50:18

标签: bash testing 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

这也无济于事:

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

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

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

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

2 个答案:

答案 0 :(得分:4)

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

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

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

  • 不要将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

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

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

diff "${t/.in}.out" <($parser_test <"$t" 2>&1)

答案 1 :(得分:1)

在你的第二个测试中,你正在捕获标准错误,但是在第一个测试中(和管道示例)stderr仍然没有被捕获,也许这就是“差异”(双关语)。

您可以在适当的位置添加'2&gt;&amp; 1'来合并stderr和stdout流。

.eg。

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

更不用说,你没有说“什么不行”意味着,这是否意味着它没有找到差异,或者它是否以错误信息退出?如果您需要更多信息,请澄清。