Bash Command Line Chain Operators in Linux with Examples

Written by: Bobbin Zachariah   |   Last updated: July 12, 2022

Linux command chaining is a technique of combining several commands so that each of them can execute after the other based on the operator between them. The operator that separates these commands is the most important aspect of command line chaining. These operators control how these commands get executed. To reword, they control the flow of execution. Linux command chaining is very useful if you want to execute multiple commands at one goal.

Chaining Operators in Linux

Below are some commonly used chaining operators which you can use with different commands:

Chaining OperatorDescription
& (Ampersand)This send a command, script, or process to the background. In short, it makes a command run in the background.
&& (Logical AND)The && operator will only execute the second command if the first command SUCCEEDS! , in other words if the first command exists with a zero status.
|| (Logical OR)It's much more like an else statement in programming. The || will only execute the second command if the first command fails. In other words, if the first command exits with a none zero status code.
; (Semi-colon)The command following this operator will execute even if the command preceding this operator is not successfully executed.
! (NOT)The NOT is much like the except statement. It will run all the commands except a given condition. It negates an expression within a command.
&&-|| (AND-OR)It's a combination of the AND OR operator. It's much like the if-else statement in programming.
| (Pipe)The output of the command preceding this operator will act as an input of the command succeeding this operator. In other words the output of another command will be given to the input of the other command.
>,>>, < (Input-OutputRedirection)Redirects the output of a command or a group of commands to a file or stream.
\ (Concatenation)Used to concatenate large commands over several lines in the shell.
() (Precedence)Allows the commands to execute in precedence order.
{} (Combination)The execution of the command succeeding this operator will depend on the execution of the first command.

Bash chain commands practical examples

Now that you understand what command line chaining is, let's look at the most common operators that allow you to chain multiple commands together.

1. Ampersand (&)

The ampersand operator is used to run a command in the background. The ampersand operator is very useful in situations where you don't want to wait for a command to finish before doing anything else.

Here's an example of how to use the ampersand operator to send processes to the background:

$ subl notes.md&
Output
[1] 105811                                                                                                                                                                  $
[1]  + done       subl notes.md
$

The ampersand operator separates your bash commands from the shell and allows them to run in the background on your system.

The number in the square brackets in the preceding example is the job number assigned by the shell to the background process. Following is the PID (Process ID) of the process assigned to it by the system. You can also see that a new shell has been returned, and the command you executed will run in the background without any issues, allowing you to enter new bash commands at the prompt.

When the background process completes, the terminal displays the following message:

[1]  + done subl notes.md

This displays the job number and status (done), as well as the command used to initiate the job.

💡 Keep in mind that even if some commands are running in the background, they can still use the terminal directly to display their output and errors.

$ ping -c 2 google.com&
Output
[1] 109863
                                                                                                                                                                         
$ PING google.com (216.58.223.142) 56(84) bytes of data.
64 bytes from jnb02s01-in-f14.1e100.net (216.58.223.142): icmp_seq=1 ttl=116 time=21.9 ms
64 bytes from jnb02s01-in-f14.1e100.net (216.58.223.142): icmp_seq=2 ttl=116 time=105 ms

--- google.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 5123ms
rtt min/avg/max/mdev = 21.869/63.525/105.181/41.656 ms

[1]  + done       ping -c 2 google.com
$

Notice, that we put our ping command in the background and a new prompt was issued, but the prompt was populated with the ping program's output as expected. When the command completes, a new prompt appears. This clearly indicates that the output of some commands may conflict with your shell prompt. To circumvent this, direct your output to a log file or /dev/null if you don't care about the output as shown below:

$ ping -c 2 google.com > ping.log&
Output
[1] 109864
$ sleep 10&  echo hello > data.txt & code& 
Output
[1] 108634
[2] 108635
[3] 108637
[2]  - done       echo hello > data.txt                                                                                                                                  

$
[3]  + done       code
$
[1]  + done       sleep 10
$

Let's move on to the next operators, but before we get to the && and || operators, I'd like to discuss the exit status code or value.

2. Exit status code

Linux commands, scripts or processes will return exit status code upon finishing execution, this returned code is stored in the environment variable $?. So, if a program successfully executes or completes execution without errors, it will return a zero exit code; if a program fails or completes execution with errors, it will return a non-zero exit code. The status code of a shell script is determined by the last command in the script.

Here is an example showing return status codes.

$ ping -c 1 idontexist.net
ping: idontexist.net: Name or service not known                                                                                                                                                                    
$ echo $?
2                                                                                                                                                                    $ ping -c 1 google.com > /dev/null                                                                                                                                                                       
$ echo $?
0                                                                                                                                                                        
$

Notice on the above command, we first attempted to ping a non-existent domain, so the ping command will fail and return a status code of 2 as expected. Finally, I tried a valid domain, and the ping was successful, returning a zero status code.

With that out of the way, let’s now move to logic AND && and logic OR || operators.

3. Logic AND (&&) operator

The command succeeding this operator will only execute if the command that precedes it is successfully executed. In other words, the second command will only be executed if the first command was successful. So the && operator will check the exit code of the command preceding it; if it is zero, the command succeeding it will be executed; otherwise, it will not. It is useful when we want to execute a command after the first command executed successfully.

Let's say we want to see if a website is online or not, and if it is, we can download the index.html file. Here's an example:

$ ping -c 1 linuxopsys.com  && wget linuxopsys.com
Output
PING linuxopsys.com (104.26.11.2) 56(84) bytes of data.
64 bytes from 104.26.11.2: icmp_seq=1 ttl=56 time=4499 ms

--- linuxopsys.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 4499.177/4499.177/4499.177/0.000 ms
--2022-07-04 00:12:23--  http://linuxopsys.com/
Resolving linuxopsys.com (linuxopsys.com)... 104.26.11.2, 172.67.70.180, 104.26.10.2, ...
Connecting to linuxopsys.com (linuxopsys.com)|104.26.11.2|:80... connected.
HTTP request sent, awaiting response... 301 Moved Permanently
Location: https://linuxopsys.com/ [following]
--2022-07-04 00:12:31--  https://linuxopsys.com/
Connecting to linuxopsys.com (linuxopsys.com)|104.26.11.2|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified 
Saving to: ‘index.html’

index.html                                     [  <=>                                                                                 ]  69.62K   143KB/s    in 0.5s    

2022-07-04 00:12:38 (143 KB/s) - ‘index.html’ saved [71294]
                                                                                                                                                                  
$

Because linuxopsys.com was up and running in the preceding example, the ping command was successfully executed, and we were able to download the index.html page of linuxopsys.com. if we try a domain that is unavailable or an unknown host, the second command will not be executed, as seen below.

$ ping -c 1 idontexist.net && wget linuxopsys.com                        
ping: idontexist.net: Name or service not known                                                                                                                                                                   
$ 

4. Logic OR (||) operator

The command following this operator will only execute if the command preceding it fails to execute. It is more akin to an else statement. If the first command's execution status is non-zero, the second command will be executed. This operator is the inverse of the logic AND operator described previously. As a result, the command that follows this operator will serve as a backup for the first command. It's as if we want to ensure that if the first command fails, the second command will back it up.

Here's an illustration: We want to see if a directory exists, and if not, we want to make one!

$           
index.html  log.txt
                                                                                                                                                                         
$ ls projects || mkdir projects && ls
ls: cannot access 'projects': No such file or directory
index.html  log.txt  projects
                                                                                                                                                                         
$

From the above snippet the first command failed and the second command acts as a backup.

5. Combined && and || operator

This command is more akin to an if-else statement. It is a combination of && and || operator.

Here is an example: We want to check if a domain is online or exists, if it's online or exists download the index.html page else print the domain is down.

$ ping -c 1 idontexist.net && wget idontexist.net || echo "THIS PAGE IS DOWN"
Output
ping: idontexist.net: Name or service not known
THIS PAGE IS DOWN

6. Semicolon(;) operator

The semicolon operator is used to run multiple commands in a row (one after the other). However, it is important to note that commands chained by the semicolon operator always execute sequentially, which means they wait for one command to finish before executing the next.

$  pwd; ls; whoami; who; id
Output
/home/linuxopsys/linux
index.html  log.txt  projects
linuxopsys
linuxopsys     :1           2022-07-03 16:55 (:1)
uid=1000(linuxopsys) gid=1000(traw) groups=1000(linuxopsys),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),109(netdev),118(wireshark),120(bluetooth),130(scanner),138(kaboxer)
                                                                                                                                                                         
$ 

If the operator separates two commands, the second command will always execute regardless of the first command's exit status. Unlike the && or || operators, the second command's execution is unaffected by the first command's exit status. Even if the first command fails to execute, in other words, the exit status code is non-zero, the second command will always run.

7. NOT(!) negation operator

It is used to negate an expression in command.

Here is a clever example in which we employ the ! to delete all the files in a current directory except for one.

$ ls
creds.txt  dog.jpg  index.html  log.txt  pet.png  projects

$ rm -rf !(index.html)

$ ls
index.html

$

Notice, all the files in our current working directory have been deleted except for the index.html file.

Tip💡

Tested the above command in both zsh and bash shells, and it does not appear to work in zsh but works perfectly in bash.

8. Piping (|) operator

The pipe operator is very handy if you want to use the output of the first command as an input of the second command.

$ cat log.txt  | wc -lc
     10      46
$ 

The command wc -l -c in the preceding example displays the number of lines and characters in a given standard input (STDIN) or file. The contents of the file log.txt are displayed by cat log.txt. The cat log.txt command outputs the contents of the file log.txt, which is then passed to the next command, wc -l -c, which counts the number of lines and characters in the input. As a result of using pipe, we get 10 lines and 46 characters in the log.txt text file. For more information on the wc command, see its man page or help.

Some commands don't support piping like the ping command as show below:

$  echo google.com | ping -c 3
ping: usage error: Destination address required

Fortunately, there is a solution to this problem. As shown below, we can use the xargs command (used to build and execute command lines from standard input) in conjunction with the ping command:

$ echo google.com | xargs ping -c 3
Output
PING google.com (172.217.170.110) 56(84) bytes of data.
64 bytes from jnb02s11-in-f14.1e100.net (172.217.170.110): icmp_seq=1 ttl=56 time=25.8 ms
64 bytes from jnb02s11-in-f14.1e100.net (172.217.170.110): icmp_seq=2 ttl=56 time=155 ms
64 bytes from jnb02s11-in-f14.1e100.net (172.217.170.110): icmp_seq=3 ttl=56 time=49.4 ms

--- google.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 25.767/76.574/154.532/55.964 ms

Notice in the previous command we used the bash command (xarg) to allow the ping command to support piping.

9. Concatenation (\) Operator

Used to concatenate large commands that have been split across several lines on the command line. This operator comes in handy when you have a long command that spans multiple lines. It also improves user readability and is used to join filenames with spaces between the words.

$  touch this\ is\ a\ file\ with\ spaces.txt

$  ls
 index.html   log.txt  'this is a file with spaces.txt'

In the previous commands, we created a file with spaces between the filename words; if the backlash is not present, the words will be treated as separate files to be created. We can also split a long command into multiple lines.

10. Input Output Redirection (‘<‘,’>’,’>>’) Operators

Redirection operators redirect the output of a command or group of commands to a stream or file. This operator can redirect standard input, standard output, or standard error.  Here's an illustration:

The first command generates a file called 'log.txt' (The > allows us to use the output of the first command as an input in the file log.txt; if the file does not exist, it will be created; otherwise, all of the contents of the file will be replaced the text "with command line chaining, which is fantastic". The second wc -c -l command prints the character and line counts in log.txt, which in this case is one line and 33 characters.

$  echo "command line chaining is awesome" > log.txt

$   wc -lc < log.txt 
 1 33

The redirection operator > overrides all file contents. Sometimes we don't want the file's contents to be replaced; instead, we want to append the new text to the end of the text file. The redirection operator >> comes in handy here.

11. Precedence operator

The precedence operator is used to set precedent value so that multiple commands can execute in a given order.

$ cmd1 && cmd 2 || cmd3 ( cmd1 && cmd 2 ) || cmd3

In the first case, if the first command is successful then the second will get executed but the third command will not execute. But in the second case, the third command will get executed as the precedence is set using the () operator.

12. Combination Operator ({})

The execution of the command succeeding this operator depends on the execution of the first command. The set of commands combined using {} operator executes when the command preceding it has successfully executed.

$ [ -f hello.txt ] && echo "file exists" ; echo "hello"
$ [ -f hello.txt ] && { echo "file exists" ; echo "hello"; }

In the first case, hello will always get printed. If the file exists then the command will get executed as it is preceding the && operator. If we want to execute both second and third commands only if the file exists, then we use {} operators to combine the commands.

Conclusion

In this guide, we've seen several ways to use the command line chaining operators within Bash. First, defined what command line chaining is. Finally, we looked at how we could use these operators to create awesome bash commands one-liners that do a certain task on the command line.

Thank you for making it this far & hopefully you found this guide helpful. Feedback is really appreciated 💜.

About The Author

Bobbin Zachariah

Bobbin Zachariah

Bobbin Zachariah is an experienced Linux engineer who has been supporting infrastructure for many companies. He specializes in Shell scripting, AWS Cloud, JavaScript, and Nodejs. He has qualified Master’s degree in computer science. He holds Red Hat Certified Engineer (RHCE) certification and RedHat Enable Sysadmin.

SHARE

Comments

Please add comments below to provide the author your ideas, appreciation and feedback.

Leave a Reply

Leave a Comment