鉴于以下测试脚本:
#!/bin/bash
# see "killing timeout": https://unix.stackexchange.com/a/57692/65781
declare -a timeout_pids
my_timeout(){
local args tp
args="$@"
timeout $args &
tp=$!
#echo "pid of timeout: $tp"
timeout_pids+=($tp)
wait $tp
}
cleanup(){
echo "-----------------------------------------"
echo "Restoring previous routing table settings"
}
pre_cleanup(){
echo "Executing pre-cleanup..."
exit
}
trap pre_cleanup INT
trap cleanup EXIT
echo "ctrl+c now to execute cleanup"
#my_timeout 9s sleep 20 2> /dev/null >/dev/null # <- does not work as expected!
my_timeout 9s sleep 20 2> /dev/null # <- works as expected
Run Code Online (Sandbox Code Playgroud)
如果启用了“不起作用”行并且脚本运行然后Ctrl+C按下;脚本立即结束,不执行陷阱。
如果删除“重定向输出到标准输出”部分(启用“按预期工作”行)然后Ctrl+C按下,则执行陷阱。
这是为什么?
Kam*_*ski 11
在其他答案建议exec &> /dev/tty,这样的陷阱写入/dev/tty不管以前的重定向:
陷阱已运行,但重定向到的标准输出
/dev/null仍在原位,因此不会打印输出。[...]exec &> /dev/tty通过重新建立从标准输出/错误到终端的连接来解决它。
有时这可能不是最好的解决方案。当您希望您的脚本(“固定”为exec &> /dev/tty)保持沉默时,请考虑一般情况。你调用
./the_script >/dev/null 2>/dev/null
Run Code Online (Sandbox Code Playgroud)
但随后陷阱被触发,/dev/tty无论如何它都会写入。
对我来说,更好的方法是以“备份”文件描述符的形式存储原始标准输出和标准错误:
# at the very beginning of the script
exec 21>&1
exec 22>&2
Run Code Online (Sandbox Code Playgroud)
然后,在陷阱函数中,您可以重定向任何单个命令:
echo "Some output" >&21
echo "Some error" >&22
Run Code Online (Sandbox Code Playgroud)
或恢复原始目的地并照常进行:
# at the beginning of the trap function
exec 1>&21
exec 2>&22
Run Code Online (Sandbox Code Playgroud)
这样,应用于中断命令的重定向就不会影响陷阱;应用于整个脚本的重定向仍然会。
陷阱已运行,但重定向到 /dev/null 的标准输出仍然存在,因此不会打印输出。尝试替换trap内容touch "$FUNCNAME"以验证,或exec &> /dev/tty通过重新建立从标准输出/错误到终端的连接来解决它。至于为什么,这可能是一个更大的功能的一部分,以便在运行陷阱时保留很多原始环境以避免出现意外。
| 归档时间: |
|
| 查看次数: |
1321 次 |
| 最近记录: |