16

Is it acceptable to return a non-zero exit code if the program in question ran properly? For example, say I have a simple program that (only) does the following:

Program takes N arguments. It returns an exit code of min(N, 255). Note that any N is valid for the program.

A more realistic program might return different codes for successfully ran programs that signify different things. Should these programs instead write this information to a stream instead, such as to stdout?

7 Answers 7

30

It depends on the environment, but I'd say it's poor style.

Unix-like systems have a strong convention that an exit status of 0 denotes success, and any non-zero exit status denotes failure. Some, but not all, programs distinguish between different kinds of failures with different non-zero exit codes; for example grep typically returns 0 if the pattern was found, 1 if it wasn't, and 2 (or more) if there was an error such as a missing file.

This convention is pretty much hard wired into Unix shells. For example, in sh, bash, and other Bourne-like shells, the if statement treats a 0 exit status as success/true, and a non-zero exit status as failure/false:

if your-command
then
    echo ok
else
    echo FAILURE
fi

I believe the conventions under MS Windows are similar.

Now there's certainly nothing stopping you from writing your own program that uses unconventional exit codes, especially if nothing else is going to interact with it, but be aware that you're violating a well established convention, and it could come back and bite you later.

The usual way for a program to return this kind of information is to print it to stdout:

status="$(your-command)"
echo "Result is $status"
2
  • 8
    +1 for explaining the convention, that approach would break most of my shell scripts were I put a set -e somewhere. Jun 22, 2012 at 20:56
  • Similarly to grep, diff returns 1 when differences are found; and >1 if an error happened.
    – 7heo.tk
    May 13, 2015 at 10:42
8

Depends on what your environment expects.

My favorite for wierdness, from Wikipedia:

In OpenVMS, success is indicated by odd values and failure by even values. The value is a 32 bit integer with sub-fields: control bits, facility number, message number and severity. Severity values are divided between success (Success, Informational) and failure (Warning, Error, Fatal).

4

I think there is a precedent if the exit code is returning meaningful, relevant information to the caller and the definition of success isn't really binary. The precedent I'm thinking of is robocopy which returns a slew of different things depending on what happened.

I'll add that we always end up having some debugging because of this -- most utility assume exit code 0 == success so get freaked out when robocopy returns 1 because it copied stuff not zero because it didn't copy stuff but didn't get an error either.

2

not returning 0 for a successful run is a bad idea, because it can cause confusion for those running your program. What if some ran your program 100+ times with different input and wanted to know how many failed or completed successfully, having a single success value makes this much easier to spot differences than having many different values.

If you have a program that has multiple successful return paths that can all signify different things, I would say that is a sign your program is poorly designed.

2

I know of a case I think is acceptable. I know of a testing framework that exits with the total number of test failures. So, for example, if the test runner completes with no failed tests it exits with zero. If one test failed, even though the test runner itself ran propely, it exits with one 1. If two fail it returns 2, etc. This goes up to 250, which means "250 or more test failures".

It uses exit codes > 250 to signify abnormal exits.

While this violates convention, it works well in practice.

2
  • 3
    I don't think this does violate convention - testing is successful if there are no errors; any non-zero result code indicates failed tests.
    – Bevan
    Jun 23, 2012 at 2:57
  • 1
    That's "exiting with an error status to indicate more than 0 errors" and while it may violate the exact common semantics of the exit status, it certainly doesn't violate the larger "0 is OK, anything larger than 0 is an error" convention.
    – Vatine
    Jun 24, 2012 at 8:34
2

It really depends what you are trying to convey with the code. DB2, for example returns 100 if there is no data found, various other positive values for warnings, and negative values for errors. Oracle does something similar.

So, if there are different success states, it may be worth using varying return values.

2

A good example: man sa-update (spamassassin)

EXIT CODES

  • An exit code of 0 means an update was available, and was downloaded and installed successfully if --checkonly was not specified.
  • An exit code of 1 means no fresh updates were available.
  • An exit code of 2 means ...

In this case, exit 1 is simply an informative code. However, if I would have written the code, I would not have chosen 1 since that usually mains failure.

1
  • You're right, it's not a failure because the goal of the command is to make sure you have the latest version - and in your exit 1 case you do indeed have the latest version.
    – gnasher729
    Jan 25, 2022 at 23:39

Not the answer you're looking for? Browse other questions tagged or ask your own question.