(可能与
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 assertNull 'Unexpected output to stdout' "$(<"$stdoutF")"
…和/或应该通过强制命令的顺序工作:
diff -r "$source" "$target" \ > >(tee "${stdoutF}"; assertNull 'Unexpected output to stdout' "$(<"$stdoutF")") 2> >(tee "${stderrF}" >&2)
…和/或是否可以以某种方式开始直接取代文件?
更新:同步不是答案 – 参见下面的吉尔斯回应.
更新2:进一步讨论Save stdout,stderr and stdout+stderr synchronously.感谢您的答案!
在bash中,进程替换替换命令foo>一旦完成,(bar)即可完成. (这在文档中没有讨论.)您可以检查
: > >(sleep 1; echo a)
此命令立即返回,然后一秒钟以异步方式打印.
在你的情况下,命令完成后,tee命令只需要一点时间才能完成.添加同步功能给了足够的时间来完成,但是这并不能消除比赛条件,只要添加一个睡眠就可以让比赛更不可能出现.
更一般地说,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