Bash difference between |, &, || and &&
| : It is the pipe operator. It passes the stdout of first command to the next command.
$ echo a | echo b | echo c
c
`&`: It starts a asynchronous process.
||: It is like the boolean or operator. If the first half succeeds then don't executable the second half.
$ echo a || echo b
a
&&: It is like the boolean and operator. Executable both halves.
&& and || are straight forward. But | & executes the command as a separate script, only forwarding the stdout and stderr.
Examples:
echo aexecutes and printsa, with statuscode 0. Now since&&isandoperator,echo bis also executed but its output is not displayed on terminal. Its output is followed as stdin toecho cwhich printsc.
$ echo a && echo b | echo c
a
c
- asd is not a command and trying to execute it fails. Then
echo bdoesn't execute as&&is and operator. Since,echo bdoesn't execute there is nothing to pass through|pipe operator. Hence,echo cdoesn't execute.
$ asd && echo b | echo c
zsh: command not found: asd
- Executing
asdfails and empty stdout ofasdis passed via|operator resulting in execution of echo c.
$ asd |echo c
c
zsh: command not found: asd
asdfails resulting inecho bnot being executed with overall statuscode1. So,||being theorboolean operator executes second halfecho c.
$ asd && echo b || echo c
zsh: command not found: asd
c
echo trueexecutes. Passing true as stdin toasdcommand. Butasdfails.
$ echo true | asd
zsh: command not found: asd
- As
echo ais async. A separate threadTis started for it and context moves toecho b, which prints b. ThenTfinishes and its stdout and stderr is displayed.
$ echo a & echo b
[1] 51810
b
a
[1] + 51810 done echo a
- d is created in root directory instead of the
dirfolder. This meanscd cmdis executed indifferent environmentor as aseparate scriptand its stdout is piped resulting intouch dbeing executed.
This is similar to having a script a.sh with cd dir in it and running ./a.sh | touch d command.
$ ls
cmd/
$ cd cmd | touch d
$ ls
cmd/ d
$ rm -rf d
$ echo cd cmd > a.sh && chmod +x a.sh
$ ./a.sh | touch d
$ ls
dir/ d
This behavior is similar to & , but & executes first cmd in separate thread.
Now, why I tried to figure out how these operator differs?
Reason is I was trying to execute many commands together as one-liner. But I needed to handle error as sometimes some of the commands failed . I tried using || , but if first command didn't fail then next command will be skipped. I tried |, but with cd dir | touch d, it generated d file in root directory instead of d directory. As with both | and &, the first command is executed in a different envionment or as a separate script, they aren't the best solution.
Conclusion: Instead of combining commands in one line , spread them in multiple lines. :)