The exit status of a process is encoded as a value between 0 and 255, so that's all you can use as an exit code. If you pass a value outside that range, most shells use the remainder modulo 256. Some shells allow a wider range of integer values for functions.
The only rule for exit codes is that 0 means success and any other value means failure. This rule goes beyond unix: it's also a common convention on other operating systems (including DOS, Windows, and many embedded systems that have a notion of exit code, but VMS does things differently). In unix systems, it's baked into the shell's boolean constructs (if, while, &&, ||, !, set -e, …), into make, and followed by all the standard utilities. In POSIX C programs,EXIT_SUCCESS is 0 and EXIT_FAILURE is some non-zero value (usually 1).
There is no rule (de facto or de jure) regarding the choice of exit codes for failure. Only a few POSIX utilities mandate specific failure status codes:
- The
! shell operator returns 1 if its operand returns 0. The && and || operator pass the status from the last command.
cmp and diff return 1 for different files and ≥2 for error conditions.
expr returns 1
if the expression evaluates to zero or null, 2 for an invalid expression, and ≥3 for other errors.
grep returns 1 for “not found” and ≥2 for error conditions. Many search commands follow this (but not find, which returns 0 if no file matches).
mesg returns 0 for yes, 1 for no, and ≥2 for error.
patch returns 1 if a hunk was rejected and ≥2 for other errors.
sort -c returns 1 if the file data isn't sorted and ≥2 for errors.
compress and localedef define some small values for specific errors.
There is a common, but not universal idea that larger values mean worse failures. For commands that test a boolean condition such as grep (is this pattern present?) and diff (are these files identical?), 1 means “no” and higher values indicate an error. In addition, values from 126 up are rarely used, as they are baked into the shell (and POSIX commands command, env, nice, nohup and time):
- 126 and 127 indicate a failure to invoke an external command;
- values above 128 in
$? indicate a command that was terminated by a signal.
/usr/include/sysexits.h lists some values with their meanings, but it's from sendmail and I've never seen it outside programs that are unrelated to email delivery.
In summary, return 0 for success, and either 1 or 2 for failure. If you need to distinguish between failure cases, start at 1 and increase the value for worse failures.