Difference between | and ||

What is the difference between | and || ?

When I run this command :

ls -la | id

I get the result of id

When I run this command :

ls -la || id

I get the result of ls -la

So what is the difference between them ?


| is the pipe operator, which passes the output of the first command to the one that follows.

from man bash:

A pipeline is a sequence of one or more commands separated by the character |. The format for a pipeline is:

[time [-p]] [ ! ] command [ | command2 ... ]

The standard output of command is connected via a pipe to the standard input of command2.

In the example you provide, id doesn't seem to do anything with the output of ls so it just returns the same output as running id alone.


|| is the logical OR operator, and specifies what to do if the first command returns false or fails (is non-zero).

from man bash:

The control operators && and || denote AND lists and OR lists, respectively. An AND list has the form

command1 && command2

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

An OR list has the form

command1 || command2

command2 is executed if and only if command1 returns a non-zero exit status. The return status of AND and OR lists is the exit status of the last command executed in the list.

In your example, ls -la runs successfully so the id command isn't run. If you did the following:

ls -z || id

and try to pass an invalid option z to ls, then it fails and the id command gets run.


| is the pipe operator. From this man sh:

A pipeline is a sequence of one or more commands separated by |. The standard output of each command but the last is connected by a pipe(2) to the standard input of the next command. Each command is run as a separate process; the shell waits for the last command to terminate. The value of a pipeline is the exit status of its last command.

A | B | C

Will take the standard output of A (what it prints to the screen) and give it to B as standard input, like what you would type in an interactive mode, and B gives its stdout to C.

history | grep word

history prints all of your shell's history, and grep prints lines matching a pattern, so this finds every entry in your shell history where you've used word, because grep reads STDIN when not given a filename as an argument.

history | tail -n10 | head -n5 

Gets the first 5 lines of the last 10 lines of history, because tail and head both read STDIN when no filename is given.


On the other hand, || is the logical OR operator, exactly equivalent to the same operator in C and C-like languages. Again, from that man sh:

The symbols && and ||, respectively, cause the list following to be executed only if the preceding pipeline returns a zero or non zero value, respectively. Newlines may appear in a list, instead of semicolons, to delimit commands.

stat filename || echo "no such file or directory" 
stat filename && echo "file exists"

If stat doesn't find the filename, it returns a nonzero exit status, and if it does, it exits successfully with 0. This is the inverse of C. (Highly contrived examples as stat gives such information anyways.)

These are essentially the same as, but shorter than, checking the last command's exit status explicitly:

stat filename
if [ $? -gt 0 ]; then
  echo "no such file or directory"
fi

etc.