How to check for command exit code inside if statement

8,097

Solution 1

Your script is not doing what you want because, when timeout -t 10 command has an exit status of 0 -- which is the exit status that is regarded as true in shell scripting -- the command timeout -t 10 command || [ $? = 143 ] just completes with an exit status of 0 and does not cause the right-hand side of || to be run. Similarly, if you replaced || with &&, then any nonzero exit status from the left-hand side would be the exit status of the whole command and the right-hand side would not be run.

You should just run them as two separate commands by separating them with a ; or a newline. If necessary, you can still use them both as the if condition when you do that (see below).

I am assuming that it is the exit status of timeout -t 10 command, and not command (if different), that you need. Otherwise it is unclear to me what you want; like ilkkachu, I am unfamiliar with a timeout command that accepts a -t option. Normally I would suggest that you do it this way, except that it sounds like your "external constraint" might prohibit it, since it doesn't use if at all:

timeout -t 10 command
test "$?" -eq 143
exit

The test/[ command returns an exit code of 0 to indicate true and 1 to indicate false, which is why you don't have to write separate branches with exit 0 and exit 1. The exit builtin, when run with no arguments, causes the shell to return the exit status of the last command that ran.

If you are already at the end of the script, then you can omit exit, because when control flows off the end of a script, it has the same effect as exit:

timeout -t 10 command
test "$?" -eq 143

(In either case, you can write [ "$?" -eq 143 ] instead of test "$?" -eq 143 if you like. See below for details on [/test usage.)

Although your description made it sound like you cannot use that code exactly, you should nonetheless be able to modify it to take the required form. You said you must not merely do the check but also start the command in the if clause. This seems to prohibit the readable and idiomatic approach suggested by Hauke Laging of running the command before the if.

So if you can't do that, then you can include the command in the if condition as you were doing, but separate it from your test/[ command with a ; rather than a ||:

if timeout -t 10 command; [ "$?" -eq 143 ]; then
    exit 0
else
    exit 1
fi

(You can get away with omitting " " around $?. You can also get away with writing = instead of 143, though it is confusing because = signifies textual rather than numeric comparison. You can write test "$?" -eq 143 instead of [ "$?" -eq 143 ] if you like.)

The reason this works is that you are permitted to write an if condition that consists of multiple commands separated by semicolons or even newlines. That's why the shell grammar requires you to write then to indicate the end of the if condition. Therefore you do not have to attempt circuitous usage of the && or || operator when your goal is to run two commands as an if condition while causing if to itself test only the second.

Note that I am only suggesting this because you said it had to all be in the if condition. I don't recommend scripting like that when you don't have to.

Solution 2

timeout -t 10 command
if [ $? -eq 143 ]; then
    exit 0
else
    exit 1
fi
Share:
8,097

Related videos on Youtube

Dremor
Author by

Dremor

Updated on September 18, 2022

Comments

  • Dremor
    Dremor almost 2 years

    I'm trying to return a 0 exit code if a command exit with the a code 143 (timeout, from the "timeout command"), 1 otherwise. Due to external constraint (CI script), I have to start the command and do the check in the if clause.

    Here is what I currently use :

    if timeout -t 10 *command* || [ $? = 143 ]
    then exit 0
    else exit 1
    fi
    

    At the moment, it always exit with a 0 code.

    • ilkkachu
      ilkkachu about 6 years
      what timeout command is that? Does it return the exit code of the command it runs?
    • ilkkachu
      ilkkachu about 6 years
      I'm asking because the one I know (in GNU coreutils, man page) doesn't take a -t flag and returns 124 on timeout, the same seems to apply to the FreeBSD one.
  • ilkkachu
    ilkkachu about 6 years
    What if timeout returns 0?
  • Hauke Laging
    Hauke Laging about 6 years
    @ilkkachu I just corrected the if handling. I have no idea whether the semantics are useful.
  • Dremor
    Dremor about 6 years
    After reading your answer, I tried an one-liner version as following: if timeout -t 30 command; [ "$?" -eq 143 ]; then exit 0; else exit 1; fi. It worked quite well.