0

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

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

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

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

4

2 回答 2

4

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

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

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

  • 不要lsfor循环一起使用(它有很多问题,例如包含空格的文件名中的意外行为);相反,使用:for t in $TESTS_PATH1/cmd*.in; do
  • 要支持带空格的文件名,请引用您的变量扩展:"$t"而不是$t
  • 不要使用反引号;它们已被弃用,取而代之的是$(command)
  • 不要使用 subshel​​l 来分类一个文件;相反,只需运行:$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

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

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

diff "${t/.in}.out" <($parser_test <"$t" 2>&1)
于 2013-05-13T15:07:18.870 回答
1

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

您可能可以在适当的位置添加一个 '2>&1' 来组合 stderr 和 stdout 流。

。例如。

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

更不用说,您没有说“不起作用”是什么意思,这是否意味着它没有发现差异,或者它退出并显示错误消息?如果您需要更多信息,请澄清。

于 2013-05-13T14:55:06.530 回答