Check exit code of Linux command

Today I found one issue in one of our legacy scripts about how to check exit code of Linux command. In this post, I will review how to check exit code of Linux command and handle it.

Let’s see the issue in the legacy script firstly, it has below lines:

printf "Starting All Services...\n" >> $logfile
{ echo $username; echo $password; echo $adminpass; } | $PROG -nopromptmsg > $SERVICE_LOG;
printf "100%% complete";

Due to company information policy, I will not provide the real name of $PROG here. The purpose of above lines is, run $PROG to start up services and output the msg to $SERVICE_LOG. Obviously, the pitfall here is, it doesn’t check the exit code of $PROG. For example, if the database is down or listener is not up, the $PROG will be error out with below message,

PROG.sh: Database connection could not be established. Either the database is down or the credentials supplied are wrong.

USAGE: 	PROG.sh ...
...
adstrtal.sh: exiting with status 1

As in the script it doesn’t check the exit code, it will just simply print “100% complete” in the log wrongly. Let’s see how to check the exit code of a command. When a command finishes execution, it returns an exit code. Linux expands its latest command exit code into variable $?. For example,

1. ls — it completed successfully.

2. echo $? — it returns 0 as 1. ls completed successfully.

3. ls notexist.txt — it errors out with message ‘ls: cannot access notexist.txt: No such file or directory’.

4. echo $? — it returns 2 as 3. errors out.

5. echo $? — it returns 0 as 4. echo $? completed successfully.

luhuang@luhuang:~/example$ pwd
/home/luhuang/example
luhuang@luhuang:~/example$ ls
luhuang@luhuang:~/example$ echo $?
0
luhuang@luhuang:~/example$ ls notexist.txt
ls: cannot access notexist.txt: No such file or directory
luhuang@luhuang:~/example$ echo $?
2
luhuang@luhuang:~/example$ echo $?
0
luhuang@luhuang:~/example$

Summary: For the shell’s purposes, a command which exits with a zero exit status has succeeded. A non-zero exit status indicates failure. The return value of a command is its exit code or 128+N as the exit status if a command terminates on a fatal signal whose number is N. Let’s see some common exit codes.

Exit Code Result
0 (Zero) Success
Non-zero Failure
2 Incorrect usage
127 Command Not found
126 Not an executable
luhuang@luhuang:~/example$ iamnotacommand
iamnotacommand: command not found
luhuang@luhuang:~/example$ echo $?
127
luhuang@luhuang:~/example$ touch iamnotaexecutable
luhuang@luhuang:~/example$ ./iamnotaexecutable
bash: ./iamnotaexecutable: Permission denied
luhuang@luhuang:~/example$ echo $?
126

See how are they defined in Linux:

luhuang@luhuang:~/example$ tail -25 /usr/include/sysexits.h
 */

#define EX_OK		0	/* successful termination */

#define EX__BASE	64	/* base value for error messages */

#define EX_USAGE	64	/* command line usage error */
#define EX_DATAERR	65	/* data format error */
#define EX_NOINPUT	66	/* cannot open input */
#define EX_NOUSER	67	/* addressee unknown */
#define EX_NOHOST	68	/* host name unknown */
#define EX_UNAVAILABLE	69	/* service unavailable */
#define EX_SOFTWARE	70	/* internal software error */
#define EX_OSERR	71	/* system error (e.g., can't fork) */
#define EX_OSFILE	72	/* critical OS file missing */
#define EX_CANTCREAT	73	/* can't create (user) output file */
#define EX_IOERR	74	/* input/output error */
#define EX_TEMPFAIL	75	/* temp failure; user is invited to retry */
#define EX_PROTOCOL	76	/* remote error in protocol */
#define EX_NOPERM	77	/* permission denied */
#define EX_CONFIG	78	/* configuration error */

#define EX__MAX	78	/* maximum listed value */

#endif /* sysexits.h */
luhuang@luhuang:~/example$

Ok, let me improve the legacy code to check the exit status.

printf "Starting All Services...\n" >> $logfile
{ echo $username; echo $password; echo $adminpass; } | $PROG -nopromptmsg > $SERVICE_LOG;
STATUS=$?
if [ $STATUS -eq 0 ];then
   printf "100%% complete \n" >> $logfile;
else
   printf "Failed to start services \n" >> $logfile;
   exit 1;
fi

So, by using STATUS=$? and verifying its value, the script could fail out if $PROG could not return exit 0.