Bash进程替换和同步

时间:2010-12-20 11:22:05

标签: bash process-substitution

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

在一些Bash单元测试脚本中,我使用以下技巧来记录显示命令的stdout和stderr:

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

此过程会向stdout生成一些输出,因此$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 and stdout+stderr synchronously。谢谢你的答案!

3 个答案:

答案 0 :(得分:27)

在bash中,只要foo > >(bar)完成,进程替换替换命令foo就会完成。 (文档中未对此进行讨论。)您可以使用

进行检查
: > >(sleep 1; echo a)

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

在您的情况下,tee命令只需要一点点时间就可以完成command。添加sync会让tee有足够的时间来完成,但这不会消除竞争条件,只不过添加sleep就可以了,它只会使竞赛更不可能显现。< / p>

更一般地说,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
    
  • 为每个命令使用不同的临时文件名,而不是重用$stdoutF$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
    

答案 1 :(得分:1)

我有时会放一个警卫:

: > >(sleep 1; echo a; touch guard) \
  && while true; do
    [ -f "guard" ] && { rm guard; break; }
     sleep 0.2
  done    

答案 2 :(得分:-1)

插入sleep 5或其他代替sync来回答您的上一个问题