在读取循环中,Bash脚本不会捕获SIGINT

时间:2014-03-25 18:02:28

标签: bash shell

我有几个带有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。我看了一下这显然是因为调用sttystdin从文件/foo/bar重定向。所以我将trap电话改为trap "break" SIGINT SIGHUP SIGTERM并且有效。

1 个答案:

答案 0 :(得分:4)

事实证明问题是由于我的cleanup函数正在调用sttystty显然不喜欢在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函数。