15

Today I opened gnome-terminal and I wrote

ls && sleep 4 && gnome-terminal

to open another terminal after the completion of ls command and waiting for 4 seconds.
So it successfully opened a new terminal after previous commands completely ran (including sleep 4).

After that, next time I typed a new command

ls -lR && sleep 4 && gnome-terminal

The command ls -lR completed after 3 seconds, but after that none of the commands sleep 4 and gnome-terminal ran successfully.

What is the problem?

wjandrea
  • 14,236
  • 4
  • 48
  • 98

2 Answers2

31

&& means to run it if the previous command was successful. In Unix that generally means exit status 0.

$ ls barfoofba && echo "This will not be echo'd"
ls: cannot access 'barfoofba': No such file or directory
$ ls bar && echo "This will be echo'd"  
This will be echo'd

In the first instance, ls did not succeed, so it exited with a non-zero exit status, and bash did not run the second command.

In the second example, I ls'd a existing file, so ls exited with 0 as exit status, and the command was executed.

If you want to run commands unconditionally, e.g. not dependent on the result of the first, you may separate them with ; like this

 command1; command2; command3 

and so forth.

Thus you may do

ls -lR ; sleep 4 ; gnome-terminal

In addition to && and ; you have || which is the opposite of &&: Only run the command if the previous command failed with a non-zero exit status. If the first command succeeds, the next will not be executed. If it fails, the next will be executed.

So in short:

  • &&: Run if preceding command exited with 0
  • ;: Run unconditionally
  • ||: Run if preceding command exited with a non-zero exit status.
  • &: Run both commands in paralell, the first in background and second in foreground.
vidarlo
  • 22,691
  • 1
    Woah, from the perspective of someone who is not too experienced with bash, this seems to go againts conventions with regards to programming. I would expect a zero value to short-circuit the && conditon and not run the following command. And vice versa for the || operator. – Cave Johnson Jan 28 '19 at 23:00
  • 7
    I think of it like 0 means SUCCESS which is like true. – Jason Goemaat Jan 29 '19 at 00:00
  • Why is ls -l && sleep 4 && gnome-terminal working but ls -lR && sleep 4 && gnome-terminal not working ? You can try on your machine.. – Abhishek Kamal Jan 29 '19 at 01:40
  • 4
    @KodosJohnson In the C world, 0 means success because non-zero means an error, and there could be hundreds of error codes (see error.h). Happy return codes are all alike... – chrylis -cautiouslyoptimistic- Jan 29 '19 at 02:48
  • 4
    @AbhishekKamal No, I can't try on my machine. ls -lR should work, but it might fail if it for instance hits one directory it doesn't have permissions to look in. For instance will ls -lR / always fail... – vidarlo Jan 29 '19 at 05:53
  • FYI, the correct conjugation for echo is echoed, not echo'd – Jon Bentley Jan 29 '19 at 12:31
  • 2
    @JonBentley The "echo" in "echo'd" is the name of a command, not an English verb, even if it happens to be spelled the same, so it's somewhat open to question how it should be conjugated. This is more obvious if you pick other commands: what would the past tense of ls be, for instance? – IMSoP Jan 29 '19 at 15:29
  • 2
    @chrylis: No, the point is exactly that "0 for true" is not how it is "in the C world". In the C programming language, conditionals (and the logical operators) consider 0 to be false and everything else to be true. The convention for process exit codes in the shell is exactly the opposite. -- Even though both C and the shell are both parts of a larger Unix tradition. – hmakholm left over Monica Jan 29 '19 at 16:55
  • @HenningMakholm I said 0 is "success", not "true". That's why you see if (!function()) everywhere in C. – chrylis -cautiouslyoptimistic- Jan 29 '19 at 17:38
12

The command ls -lR exited with an exit-status different than zero, so the following commands have not been executed. Most probably ls was unable to open a subdirectory. It didn't happen in your first command because you didn't use the -R-option.

From man bash:

        command1 && command2
       command2  is  executed if, and only if, command1 returns an exit status
       of zero.

From man ls:

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).
mook765
  • 15,925