我有几个带有while read line
循环的脚本,当我按下Ctrl C时,它们不执行我的清理功能。例如:
#!/bin/bash
cleanup() {
stty echo
exit 0
}
trap cleanup SIGINT SIGHUP SIGTERM
stty -echo
while read -r line; do
echo "$line"
done < /foo/bar
cleanup
当我按下Ctrl-C时,我的终端被搞砸了,因为stty -echo
设置仍然有效。我有许多其他脚本,我的清理功能完美无缺。我似乎遇到问题的唯一一次是当我在脚本处于read
循环时按Ctrl-C。当脚本在cleanup
循环内时,有没有办法确保在按下Ctrl-C时调用read
函数?或者我只是遗漏了一些明显的东西?
更新:我的脚本中还有其他内容。我运行上面的确切脚本,我不能让它失败,就像我的其他脚本一样。我将不得不尝试将破碎的脚本提炼为我可能失败的东西,此时我将更新问题。
更新2:好的,我明白了。我从stty
得到了一个错误(我没有看到,因为我的真正的清理功能也在清除屏幕)。错误是:stty: standard input: Inappropriate ioctl for device
。我看了一下这显然是因为调用stty
而stdin
从文件/foo/bar
重定向。所以我将trap
电话改为trap "break" SIGINT SIGHUP SIGTERM
并且有效。
答案 0 :(得分:4)
事实证明问题是由于我的cleanup
函数正在调用stty
,stty
显然不喜欢在stdin
调用时调用从文件重定向。因此,当我在脚本执行read
循环时按下Ctrl-C时,cleanup
函数被调用,就像我从循环中调用它一样:
while read -r line; do
...
cleanup
...
done < "$filename"
反过来,这意味着stty
被重定向的stdin
执行,并且因错误stty: standard input: Inappropriate ioctl for device
而死亡。
我可以通过更改trap
行来解决此问题:
trap "break" SIGINT SIGHUP SIGTERM
因此,当我按下Ctrl-C时,它不是有效地将cleanup
的调用插入到我的循环中,而是仅仅(有效地)将break
插入到循环中,从而打破了循环并随后通过循环后的行调用cleanup
函数。