Search code examples
bashexit-code

bash $? is always zero at the head of a file


$? returns the exit status of the latest executed command. It runs correctly in a terminal. However, if I refer $? at the head of a file, it returns always zero even though I run a command which ends with a non-zero exit status in a terminal before. For example,

$ cat foo.txt; echo $?
cat: foo.txt: No such file or directory
1
$ cat foo.txt; ./test.sh
cat: foo.txt: No such file or directory
0

, where test.sh is

#!/bin/bash
echo $?

Is this a correct behavior? (I use GNU bash, version 4.4.12).


Solution

  • It is because a script started with #!/bin/bash always starts a new sub-shell and the exit code from the previous shell shell is lost. The last run exit codes are retained only in the current instance and not propagated to children

    See output below. I've added a new line echo $BASHPID after echo $? to print the current process instance of the new shell (seen from BASHPID). As you can see the varying numbers for the one in the failure case and the one in running the script.

    echo $BASHPID; cat nosuchfile; bash script.sh
    8080
    cat: nosuchfile: No such file or directory
    0
    9040
    

    You could see from here that 8080 is the pid of the parent shell instance from which a new shell instance with pid 9040 was spawned to run your script.

    But you can expect your behavior to be seen when sourcing the script which runs the script in the same shell instance as you can see above.

    echo $BASHPID; cat nosuchfile; source script.sh
    8080
    cat: nosuchfile: No such file or directory
    1
    8080
    

    Here the exit code 1 corresponds to the one thrown by cat for not able to be open the file.

    Modified script.sh

    #!/bin/bash
    echo $?
    # Print current shell process id
    echo $BASHPID