20

(可能与Do some programs not accept process substitution for input files有关?

在一些 Bash 单元测试脚本中,我使用以下技巧来记录显示命令的标准输出和标准错误:

command > >(tee "${stdoutF}") 2> >(tee "${stderrF}" >&2)

这个过程产生一些输出到标准输出,所以$stdoutF文件得到一些数据。然后我运行另一个不输出任何数据的命令:

diff -r "$source" "$target" > >(tee "${stdoutF}") 2> >(tee "${stderrF}" >&2)

但是,在运行空性测试之前,这个过程并不总是成功完成(使用shunit-ng):

assertNull 'Unexpected output to stdout' "$(<"$stdoutF")"

在 100 次运行测试中,这失败了 25 次。

sync在测试文件是否为空之前调用是否足够:

sync
assertNull 'Unexpected output to stdout' "$(<"$stdoutF")"

...和/或它是否应该通过强制命令的顺序来工作:

diff -r "$source" "$target" \
> >(tee "${stdoutF}"; assertNull 'Unexpected output to stdout' "$(<"$stdoutF")")
2> >(tee "${stderrF}" >&2)

...和/或是否有可能以tee某种方式assertNull直接而不是文件?

更新sync不是答案 - 请参阅下面 Gilles 的回复。

更新 2:进一步讨论Save stdout、stderr 和 stdout+stderr synchronously。感谢您的回答!

4

3 回答 3

30

在 bash 中,进程替换替换命令foo > >(bar)在完成后立即foo完成。(这在文档中没有讨论。)你可以检查这个

: > >(sleep 1; echo a)

a此命令立即返回,然后在一秒后异步打印。

在您的情况下,该tee命令在完成后只需一点时间即可command完成。添加sync给了tee足够的时间来完成,但这并不能消除竞争条件,就像添加一个sleep将一样,它只会使竞争更不可能出现。

更一般地说,sync没有任何内部可观察的影响:只有当您想要访问文件系统存储在不同操作系统实例下的设备时,它才会有所不同。更清楚地说,如果您的系统断电,则只有在上次写入之前写入的数据才能sync保证在您重新启动后可用。

至于消除竞争条件,这里有一些可能的方法:

  • 显式同步所有替代进程。

    mkfifo sync.pipe
    command > >(tee -- "$stdoutF"; echo >sync.pipe)
           2> >(tee -- "$stderrF"; echo >sync.pipe)
    read line < sync.pipe; read line < sync.pipe
    
  • 为每个命令使用不同的临时文件名,而不是重复使用$stdoutFand $stderrF,并强制临时文件始终是新创建的。

  • 放弃进程替换并改用管道。

    { { command | tee -- "$stdoutF" 1>&3; } 2>&1 \
                | tee -- "$stderrF" 1>&2; } 3>&1
    

    如果需要命令的返回状态,bash 将其放入${PIPESTATUS[0]}.

    { { command | tee -- "$stdoutF" 1>&3; exit ${PIPESTATUS[0]}; } 2>&1 \
                | tee -- "$stderrF" 1>&2; } 3>&1
    if [ ${PIPESTATUS[0]} -ne 0 ]; then echo command failed; fi
    
于 2010-12-20T20:21:48.143 回答
1

我有时会设置一个警卫:

: > >(sleep 1; echo a; touch guard) \
  && while true; do
    [ -f "guard" ] && { rm guard; break; }
     sleep 0.2
  done    
于 2016-05-12T17:15:36.040 回答
-1

插入一个sleep 5或诸如此类的东西来代替sync回答您的最后一个问题

于 2010-12-20T17:41:08.230 回答