在我的 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 zsh
shell(以及其他一些类似 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
也应该适用于大多数系统)。