我想在bash脚本中提供一个可选的日志参数,并使用exec
从一开始就tee
一个管道。但是,打开tee
进程会导致脚本挂起,我认为是因为stdout没有关闭:
# Output to a log file, if set
if [[ $OPT_LOG ]]; then
exec > >(tee -a $OPT_LOG)
fi
我试图关闭:
exec >&-
但它仍然挂起 - 是否还有其他正确关闭tee
的方法,以便脚本在执行结束时正常退出?
似乎由于shell脚本未退出,使用tee
会导致提示符($PS1
)不再出现。作为解决方法,我通常在调用tee
后使用短暂的sleep
。
#!/bin/bash
exec > >(tee -a mylog)
sleep .1
# my code
将注释转换为答案,并进行小的编辑。
我注意到:
The following code exits OK for me on Mac OS X 10.10.3.
OPT_LOG=file.name if [[ $OPT_LOG ]] then exec > >(tee -a $OPT_LOG) fi for ((i = 0; i < 10; i++)) do echo "Logging message $i at $(date)" sleep 1 done
Your problem is probably in the code you've not shown. What commands are you running? What do you get from
bash -x yourscript.sh
?
If you remove the sleep and date calls from your example, the script does not exit properly any more, as told by Andrew:
OPT_LOG=file.name; if [[ $OPT_LOG ]]; then exec > >(tee -a $OPT_LOG); fi; for ((i = 0; i < 10; i++)); do echo "Logging message $i"; done
我回答道:
这是一个有趣的观察!我可以重现你的结果。
我做了一些实验:
pwd
,只是输出,但这并没有影响到结果(但pwd
可能是Bash内置的命令)。bash -c 'exit 0'
(这不是内置命令),代码正常终止。> >(tee -a $OPT_LOG &)
,但输出没有出现在屏幕或文件中。(我觉得这很奇怪,但这只是一种尝试性的解决方法,不是主要工作的一部分。)我的印象是Andrew发现了Bash的一个bug,可以进行报告。(请参阅Bash手册上的Reporting Bugs了解如何报告。)我认为,如果没有执行任何外部命令,那么不退出是不正确的。我可以确认苹果的Bash 3.2.57有这个问题;Bash 4.3.27也有这个问题(我自己构建的,因此修补了ShellShock漏洞的修复程序)。
相对不常见的是,shell脚本没有调用任何外部命令,在exec重定向之后调用任何外部命令似乎都会抑制这个bug。
它还证实了chatraed的解决方法有效,尽管比最小必要的更慢。对于生产使用,我会选择sleep 0
,它比sleep 0.1
快近十分之一秒。只睡眠几分之一秒仅适用于某些系统;经典地(并根据POSIX),sleep
不会睡眠小数秒。另一方面,如果你写sleep 0.1
,在不支持小数秒的系统上,包括前导的0
可能使它睡眠零秒;写.1
可能有相同的效果,也可能没有。
help
提取shell内置命令列表,并检查它们的行为是否一致。 - Eugeniu Rosca
(我原来的唯一分号是
then`前面的那个,而且只是因为我从问题中复制了代码 - 这不是我编写shell脚本的方式)。你的问题可能在你没有展示的代码中。你运行什么命令? 从bash -x yourscript.sh得到什么? - Jonathan Lefflersleep
和date
调用,根据 Andrew 的说法,脚本将不再正常退出:OPT_LOG=file.name; if [[ $OPT_LOG ]]; then exec > >(tee -a $OPT_LOG); fi; for ((i = 0; i < 10; i++)); do echo "Logging message $i"; done
- Eugeniu Roscasleep 0
可能很好和快速之外。另外,一个 shell 脚本不调用任何外部命令相对不寻常,在exec
重定向后调用任何外部命令似乎可以抑制这个 bug。 - Jonathan Leffler