“kill -PIPE $$”与“exit 1”之间有什么区别?

“kill -PIPE $$”与“exit 1”之间有什么区别?

在我的 Bash 脚本中,我使用以下语法来退出 Bash 脚本:

kill -PIPE $$

我使用它是因为有时在脚本的函数或内部 shell 中,并exit 1没有真正从 Bash 脚本中退出。

所以我用kill而不是exit 1.

看起来

exit 1

kill -PIPE $$

几乎相等。我的假设是真的吗?

其次 - 关于kill -PIPE $$,使用该语法是否存在风险?

答案1

exit 1以退出代码 1 退出当前的子 shell 环境,例如:

sh -c '(echo 1; exit 1; echo 2); echo 3'

exit 1将退出在 side 中运行代码的子 shell (...),因此2不会输出,并且父 shell 进程将恢复 echoing 3

kill -s PIPE "$$"1 将 SIGPIPE 信号发送到执行当前解释脚本的 shell 解释器的进程。默认情况下,SIGPIPE 信号会导致进程终止,并且该进程已被 SIGPIPE 终止的事实反映在其退出状态中。

所以在:

sh -c '(echo 1; kill -s PIPE "$$"; echo 2); echo 3'

SIGPIPE 信号由子 shell 进程发送到其父进程(执行的进程sh)。该父进程将死亡并且不输出,3而子shell进程将继续在后台运行并输出2

bash如果您在or zshshell(以及其他一些类似 Bourne 的 shell)中运行该命令,这些 shell 会将$?参数(最后一个命令的退出状态的内部表示)设置为类似 141 的值,即 128 + SIGPIPE(大多数系统上为 13)。

现在 SIGPIPE 是系统发送给试图写入没有读取端的管道或套接字(损坏的管道/套接字)的进程的信号,因此在此处发送它有点误导。为管理性终止进程而保留的信号是 SIGTERM,这恰好是kill默认发送的信号。

现在,您可能想要使用 SIGPIPE 而不是 SIGTERM 的原因之一是,bash当其中一项工作被信号终止时,有类似的 shell 会输出一条消息,而它们通常不会对 SIGPIPE 执行此操作(因为这对于进程被 SIGPIPE 终止,并不一定意味着存在像cmd | head -n 1) 中那样的问题,因此使用 SIGPIPE 是避免这些消息的一种方法。

bash-4.4$ /bin/kill 0
Terminated
bash-4.4$ /bin/kill -s PIPE 0
bash-4.4$

即使在非交互时:

$ bash -c 'sh -c "kill \$\$"; exit'
bash: line 1:  6665 Terminated              sh -c "kill \$\$"
$ bash -c 'sh -c "kill -s PIPE \$\$"; exit'
$

1此处添加周围缺少引号$$为了可靠性并使用标准(POSIX 中非可选) kill -s PIPE可移植性语法(尽管kill -PIPE也应该适用于大多数系统)。

相关内容