-3

Why exit status is different between bash and csh shell?, In ls man:

Exit status:
       0      if OK,

       1      if minor problems (e.g., cannot access subdirectory),

       2      if serious trouble (e.g., cannot access command-line
              argument).

In order to test exit status of the command ls, let's say we have single file called ss saved in a folder. Let's list this file based on the status of it's characters using the wildcard ?

In csh Shell:

ls -d ss
ss

ls -d s?
ss

ls -d ?s
ss

ls -d ?z
ls: No match.

ls -d ?z | echo $?  #check exit status
0

In Bash:

ls -d ss
ss

ls -d s?
ss

ls -d ?s
ss

ls -d ?z
ls: cannot access ?z: No such file or directory

ls -d ?z | echo $?  #check exit status
2

It is the same command ls, but the exit status is different between csh shell and bash:

  • In csh shell the exit status is 0
  • In bash the exit status is 2

Now, the questions are:

1) Why the same command ls has difference exit status between bash and csh shell?

2) What is the importance of this difference in the command behaviour under bash and csh shell?

  • 1
    I always thought bash IS a shell ("bourne again shell")? – RudiC Oct 5 '18 at 21:39
7

First, your ls -d ?z | echo $? in Bash is not measuring what you think it is. The pipeline all starts at once, and parameter expansion happens even before that, so echo $? is printing the return code of the previous command, not the one before the pipe. Under csh, it's not even doing that. That output is meaningless. If you run them as separate commands: ls -d ?z ; echo $? you will get informative output about what the actual exit code was.

sh -c 'exit 53' will work as a command for testing whether you're really getting the exit code from where you wanted.


Second, though you haven't told us, the error in your first example sounds like csh so I'll assume it's that. In that case, ls -d ?z is not running ls at all; the shell's wildcard expansion is failing and an error ("No match") has been reported, inhibiting the command from running. Bash, by default, passes non-matching globs through literally: it runs ls '?z', in effect, and you get an error from ls because that file doesn't exist. Regardless, the error code reported was from the previous line.

So the ls command, when it ran, had the same behaviour in all cases, it just wasn't running in the first place some of the time.


You can change Bash's (frankly, bad) behaviour with shopt -s failglob. It will then error out when a glob does not match:

/tmp$ ls ?z
ls: cannot access '?z': No such file or directory
/tmp$ shopt -s failglob
/tmp$ ls ?z
bash: no match: ?z

The first will have an exit code of 2, from ls, and for the second $? will be 1, from Bash itself.

  • very nice explanation.. make sense. Many thanks ;-) – user88036 Oct 5 '18 at 22:10
  • 1
    It's probably tcsh. In csh (and tcsh) the exit status is in $status. But in tcsh, $? is also supported as an alternative. – Stéphane Chazelas Oct 5 '18 at 22:34
  • 1
    Note the difference thoug: with bash -O failglob (or zsh or fish) the command is cancelled if any of the globs fail to match while in csh, zsh -o cshnullglob and pre-Bourne Unix shells, the command is cancelled if none of the globs match any file. – Stéphane Chazelas Oct 5 '18 at 22:36
  • @Stéphane Chazelas. thank you for the highlights! – user88036 Oct 5 '18 at 22:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy