使用 tee 和 wait 时脚本挂起,为什么?

使用 tee 和 wait 时脚本挂起,为什么?

我正在运行一个脚本,该脚本可以为我的 NAS 服务器自动执行 snapraid。这是我在网上找到的一个脚本,它在 Debian 9 上运行没有问题。我上周更新到 Debian 10,该脚本现在挂在 Debian 9 上没有的地方。我想我已经将问题范围缩小到了问题的范围并等待命令。

我已将脚本缩短为以下代码片段以进行测试,并且问题正在发生,这就是为什么我认为需要等待。

#!/bin/bash

# location of the snapraid binary
SNAPRAID_BIN="/usr/local/bin/snapraid"

# redirect all output to screen and file
> $TMP_OUTPUT
exec 3>&1 4>&2
# NOTE: Not preferred format but valid: exec &> >(tee -ia "${TMP_OUTPUT}" )
exec > >(tee -a "${TMP_OUTPUT}") 2>&1

# run the snapraid DIFF command
echo "###SnapRAID DIFF [`date`]"
$SNAPRAID_BIN diff
# wait for the above cmd to finish
wait
echo
echo "DIFF finished [`date`]"

我还运行 htop 来查看发生了什么,并且从 snapraid 命令创建的进程并没有结束。

wait 正在做它应该做的事情,等等,但是为什么这个方法以前有效而不是现在呢?

完整脚本在这里:https://pastebin.com/gJqnz875

答案1

进程内部tee的替换不会退出,直到它的 stdin 上收到 eof 或发生一些错误。

EOF而且,由于它的标准输入是一个管道,因此只有当其写入端的所有句柄都关闭时,它才会在其标准输入上得到一个。

因此,您必须保存原始的 stdout 和 stderr,然后在 之前wait将它们重定向到原始文件;通过new>&old导致fd 关闭来复制 fd old

exec {out}>&1 {err}>&2
exec > >(tee -a output) 2>&1
...
exec >&$out 2>&$err
wait $(pgrep -P "$$")

此外,只有在较新版本的 bash 中,wait才会等待> >(...)进程替换中运行的进程;这就是为什么我使用wait $(pgrep -P "$$")而不是简单地使用waitpgrep -P查找其父进程的进程)。另请参阅这里对于这个和其他相关的陷阱> >(...)

相关内容