5

In my Bash script, I used the following syntax in order to exit from the Bash script:

kill -PIPE $$

I use it because sometimes in a function or in an internal shell in the script, the exit 1 does not really exit from the Bash script.

So I use kill instead of exit 1.

It seems that

exit 1

and

kill -PIPE $$

are almost equal. Is my assumption true?

Second - about kill -PIPE $$, is there a risk in using that syntax?

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
yael
  • 13,106

1 Answers1

10

exit 1 exits the current subshell environment with exit code 1, so for instance in:

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

That exit 1 exits the subshell running the code in side (...) so that 2 is not output, and the parent shell process resumes echoing 3.

kill -s PIPE "$$"¹ sends the SIGPIPE signal to the process that executed the shell interpreter currently interpreting the script. The SIGPIPE signal by default causes processes to terminate, and the fact that that process has been killed by SIGPIPE is reflected in its exit status.

So in:

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

A SIGPIPE signal is sent by the subshell process to its parent process (the one that executed sh). That parent process will die and not output 3 while the subshell process will carry on running in background and output 2.

If you ran that command in the bash or zsh shell (and a few other Bourne-like shells), those shells will set the $? parameter (their internal representation of the exit status of the last command) to something like 141, which is 128 + SIGPIPE (13 on most systems).

Now SIGPIPE is the signal sent by the system to processes that are attempting to write to a pipe or socket that has no reading end (a broken pipe/socket), so sending it here is a bit misleading. The signal reserved for administratively terminate a process is SIGTERM, that happens to be the signal kill sends by default.

Now, one reason why you may want to use SIGPIPE instead of SIGTERM is that there are shells like bash that output a message when one of their job is terminated by a signal, while they generally don't do it for SIGPIPE (as it's common for processes to be terminated by a SIGPIPE, and doesn't necessarily mean there's a problem like in cmd | head -n 1), so using SIGPIPE is a way to avoid those messages.

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

even when non-interactive:

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

1 Here adding the missing quotes around $$ for reliability and using the standard (non-optional in POSIX) kill -s PIPE syntax for portability (though kill -PIPE should also work on most systems).

kjo
  • 15,339
  • 25
  • 73
  • 114