Skip to main content
added 9 characters in body
Source Link
Stéphane Chazelas
  • 587.9k
  • 96
  • 1.1k
  • 1.7k

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, $? is 128 + n. What that means is that in those shells, if you get a $? of 129, you don't know whether it's because the process exited with exit(129) or whether it was killed by the signal 1 (HUP on 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 SIGTERM 
  • ksh93, $? is 256 + n. That means that from a value of $? you can differentiate between a killed and non-killed process. Newer versions of ksh, 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 that ksh will 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 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 

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. yash offers a compromise. It returns 256 + 128 + n. That means we can also differentiate between a killed process and one that terminated properly. And upon exiting, it will report 128 + n without 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 

Bourne-like shells also make the exit status of the last run command in their own $? variable. 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, $? is 128 + n. What that means is that in those shells, if you get a $? of 129, you don't know whether it's because the process exited with exit(129) or whether it was killed by the signal 1 (HUP on 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 SIGTERM 
  • ksh93, $? is 256 + n. That means that from a value of $? you can differentiate between a killed and non-killed process. Newer versions of ksh, 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 that ksh will 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 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. yash offers a compromise. It returns 256 + 128 + n. That means we can also differentiate between a killed process and one that terminated properly. And upon exiting, it will report 128 + n without 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 

Bourne-like shells also make the exit status of the last run command in their own $? special 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, $? is 128 + n. What that means is that in those shells, if you get a $? of 129, you don't know whether it's because the process exited with exit(129) or whether it was killed by the signal 1 (HUP on 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 SIGTERM 
  • ksh93, $? is 256 + n. That means that from a value of $? you can differentiate between a killed and non-killed process. Newer versions of ksh, 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 that ksh will 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 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. yash offers a compromise. It returns 256 + 128 + n. That means we can also differentiate between a killed process and one that terminated properly. And upon exiting, it will report 128 + n without 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 
added 22 characters in body
Source Link
Stéphane Chazelas
  • 587.9k
  • 96
  • 1.1k
  • 1.7k

Processes can call the _exit() system call (on Linux, see also exit_group()) with an integer argument to report an exit code to their parent. Though it's an integer, only the 8 least significant bits are available to the parent (exception to that is when using waitid() or handler on SIGCHLD in the parent to retrieve that code, though not on Linux).

Processes can call the _exit() system call (on Linux, see also exit_group()) with an integer argument to report an exit code to their parent. Though it's an integer, only the 8 least significant bits are available to the parent (exception to that is when using waitid() in the parent to retrieve that code, though not on Linux).

Processes can call the _exit() system call (on Linux, see also exit_group()) with an integer argument to report an exit code to their parent. Though it's an integer, only the 8 least significant bits are available to the parent (exception to that is when using waitid() or handler on SIGCHLD in the parent to retrieve that code, though not on Linux).

added 195 characters in body
Source Link
Stéphane Chazelas
  • 587.9k
  • 96
  • 1.1k
  • 1.7k
  • bash and mksh (since R41, a regression^Wchange apparently introduced intentionally) will truncate the number (positive or negative) to 8 bits. So for instance return 1234 will set $? to 210, return -- -1 will set $? to 255.
  • zsh and pdksh (and derivatives other than mksh) allow any signed 32 bit decimal integer (-231 to 231-1) (and truncate the number to 32bits).
  • ash and yash allow any positive integer from 0 to 231-1 and return an error for any number out of that.
  • ksh93 for return 0 to return 320 set $? as is, but for anything else, truncate to 8 bits. Beware as already mentioned that returning a number between 256 and 320 could cause ksh to kill itself upon exit.
  • rc and es allow returning anything even lists.
  • bash and mksh will truncate the number (positive or negative) to 8 bits. So for instance return 1234 will set $? to 210, return -- -1 will set $? to 255.
  • zsh and pdksh (and derivatives other than mksh) allow any signed 32 bit decimal integer (-231 to 231-1) (and truncate the number to 32bits).
  • ash and yash allow any positive integer from 0 to 231-1 and return an error for any number out of that.
  • ksh93 for return 0 to return 320 set $? as is, but for anything else, truncate to 8 bits. Beware as already mentioned that returning a number between 256 and 320 could cause ksh to kill itself upon exit.
  • rc and es allow returning anything even lists.
  • bash and mksh (since R41, a regression^Wchange apparently introduced intentionally) will truncate the number (positive or negative) to 8 bits. So for instance return 1234 will set $? to 210, return -- -1 will set $? to 255.
  • zsh and pdksh (and derivatives other than mksh) allow any signed 32 bit decimal integer (-231 to 231-1) (and truncate the number to 32bits).
  • ash and yash allow any positive integer from 0 to 231-1 and return an error for any number out of that.
  • ksh93 for return 0 to return 320 set $? as is, but for anything else, truncate to 8 bits. Beware as already mentioned that returning a number between 256 and 320 could cause ksh to kill itself upon exit.
  • rc and es allow returning anything even lists.
added 45 characters in body
Source Link
Stéphane Chazelas
  • 587.9k
  • 96
  • 1.1k
  • 1.7k
Loading
deleted 26 characters in body
Source Link
Stéphane Chazelas
  • 587.9k
  • 96
  • 1.1k
  • 1.7k
Loading
added 101 characters in body
Source Link
Stéphane Chazelas
  • 587.9k
  • 96
  • 1.1k
  • 1.7k
Loading
note about waitid() returning the non-truncated exit code.
Source Link
Stéphane Chazelas
  • 587.9k
  • 96
  • 1.1k
  • 1.7k
Loading
disambiguate `yash` as it seems there are several shells by that name
Source Link
Stéphane Chazelas
  • 587.9k
  • 96
  • 1.1k
  • 1.7k
Loading
added 241 characters in body
Source Link
Stéphane Chazelas
  • 587.9k
  • 96
  • 1.1k
  • 1.7k
Loading
disambiguate exit code and exit status
Source Link
Stéphane Chazelas
  • 587.9k
  • 96
  • 1.1k
  • 1.7k
Loading
added 958 characters in body
Source Link
Stéphane Chazelas
  • 587.9k
  • 96
  • 1.1k
  • 1.7k
Loading
added 356 characters in body
Source Link
Stéphane Chazelas
  • 587.9k
  • 96
  • 1.1k
  • 1.7k
Loading
added 170 characters in body
Source Link
Stéphane Chazelas
  • 587.9k
  • 96
  • 1.1k
  • 1.7k
Loading
Source Link
Stéphane Chazelas
  • 587.9k
  • 96
  • 1.1k
  • 1.7k
Loading