Bourne-like shells also make the exit status of the last run command in their own $? variablespecial parameter. However, it does not contain directly the number returned by waitpid(), but a transformation on it, and it's different between shells.
in ash, zsh, pdksh, bash, the Bourne shell,
$?is128 + n. What that means is that in those shells, if you get a$?of129, you don't know whether it's because the process exited withexit(129)or whether it was killed by the signal1(HUPon most systems). But the rationale is that shells, when they do exit themselves, by default return the exit status of the last exited command. By making sure$?is never greater than 255, that allows to have a consistent exit status:$ bash -c 'sh -c "kill \$\$"; printf "%x\n" "$?"' bash: line 1: 16720 Terminated sh -c "kill \$\$" 8f # 128 + 15 $ bash -c 'sh -c "kill \$\$"; exit'; printf '%x\n' "$?" bash: line 1: 16726 Terminated sh -c "kill \$\$" 8f # here that 0x8f is from a exit(143) done by bash. Though it's # not from a killed process, that does tell us that probably # something was killed by a SIGTERMksh93,$?is256 + n. That means that from a value of$?you can differentiate between a killed and non-killed process. Newer versions ofksh, upon exit, if$?was greater than 255, kills itself with the same signal in order to be able to report the same exit status to its parent. While that sounds like a good idea, that means thatkshwill generate an extra core dump (potentially overwriting the other one) if the process was killed by a core generating signal:$ ksh -c 'sh -c "kill \$\$"; printf "%x\n" "$?"' ksh: 16828: Terminated 10f # 256 + 15 $ ksh -c 'sh -c "kill -ILL \$\$"; exit'; printf '%x\n' "$?" ksh: 16816: Illegal instruction(coredump) Illegal instruction(coredump) 104 # 256 + 15, ksh did indeed kill itself so as to report the same # exit status as sh. Older versions of `ksh93` would have returned # 4 instead.Where you could even say there's a bug is that
ksh93kills itself even if$?comes from areturn 257done by a function:$ ksh -c 'f() { return "$1"; }; f 257; exit' zsh: hangup ksh -c 'f() { return "$1"; }; f 257; exit' # ksh kills itself with a SIGHUP so as to report a 257 exit status # to its parent
Where you could even say there's a bug is that ksh93 kills itself even if $? comes from a return 257 done by a function:
$ ksh -c 'f() { return "$1"; }; f 257; exit' zsh: hangup ksh -c 'f() { return "$1"; }; f 257; exit' # ksh kills itself with a SIGHUP so as to report a 257 exit status # to its parent yash.yashoffers a compromise. It returns256 + 128 + n. That means we can also differentiate between a killed process and one that terminated properly. And upon exiting, it will report128 + nwithout having to suicide itself and the side effects it can have.$ yash -c 'sh -c "kill \$\$"; printf "%x\n" "$?"' 18f # 256 + 128 + 15 $ yash -c 'sh -c "kill \$\$"; exit'; printf '%x\n' "$?" 8f # that's from a exit(143), yash was not killed