Mar*_*ric 4 bash signals trap select
当我将“陷阱”与选择循环结合使用时,即当我尝试在显示选项时按 CTRL+C 来中断时,它只会在终端中打印 ^C。如果我从脚本中删除“陷阱”,它通常会退出,即它会接受 CTRL+C。
我已经在两种不同版本的 bash(一种随 CentOS 一起提供,一种随 Fedora 一起提供)上对此进行了测试,我对 Fedora(4.4.23(1)-release)中的一个有问题。CentOS 附带的 Bash 版本 4.2.46(2)-release 似乎运行良好。我还在本地终端和远程(通过 ssh)测试过这个。问题总是在 Fedora 方面。
我将发布代码以查看我在说什么
这个不起作用:
#!/bin/bash
trap exit SIGINT
select opt in One Two Three; do
break
done
Run Code Online (Sandbox Code Playgroud)
如果我要删除整个 'trap exit SIGINT' 行,它将正常工作并接受 CTRL+C 没有问题。
任何想法如何解决或绕过这个?
任何想法如何解决或绕过这个?
您可以通过打开 posix 模式来绕过它,可以使用 --posix
选项,也可以暂时使用set -o posix
:
set -o posix
select opt in foo bar baz; do
echo "opt=$opt"
done
set +o posix
Run Code Online (Sandbox Code Playgroud)
有关此行为的解释,您可以查看内置zread()
函数使用的函数read
(也由 bash in 内部调用select
):
while ((r = read (fd, buf, len)) < 0 && errno == EINTR)
/* XXX - bash-5.0 */
/* We check executing_builtin and run traps here for backwards compatibility */
if (executing_builtin)
check_signals_and_traps (); /* XXX - should it be check_signals()? */
else
check_signals ();
Run Code Online (Sandbox Code Playgroud)
由于某些特殊原因,executing_builtin
仅在read
显式调用内置函数时才设置,而不是在由 调用时设置select
。这看起来很像一个错误,而不是故意的。
在 posix 模式下运行时,一个信号将取消read
内置。在这种情况下,zreadintr()
被调用,这与 不同zread()
,read(2)
在运行陷阱后不会重新调用中断的系统调用。见builtins/read.def
:
if (unbuffered_read == 2)
retval = posixly_correct ? zreadintr (fd, &c, 1) : zreadn (fd, &c, nchars - nr);
else if (unbuffered_read)
retval = posixly_correct ? zreadintr (fd, &c, 1) : zread (fd, &c, 1);
else
retval = posixly_correct ? zreadcintr (fd, &c) : zreadc (fd, &c);
Run Code Online (Sandbox Code Playgroud)
有关 bashread
内置的“重新启动”的更多详细信息,请点击此处。