1. Overview

I’m sure many of us must have seen an exclamation mark (!) in bash scripts. The exclamation mark serves a different purpose, depending on where it’s being used. It’s one of the powerful features of the Bash shell and can help to improve productivity.

In this tutorial, we’ll see the various uses of the exclamation mark in Bash.

2. Specifying the Interpreter Path

In Bash, the exclamation mark (!) is used with the pound (#) symbol to specify the interpreter path. This usage is called “shebang” and is denoted as:

#!interpreter [arguments]

In shell scripts, we can use it to specify bash as an interpreter:

$ cat welcome.sh
#!/usr/bin/bash
echo "Welcome !!!"

Similarly, we can use it in a directive in a Python script to specify the python executable as the interpreter:

$ cat welcome.py
#!/usr/bin/python
print("Welcome !!!")

Note that this directive must be the first line in the script.

3. Inverting a Command’s Exit Status

We can use the exclamation mark (!) to invert the exit status of a command. Let’s execute a command that will return a non-zero status:

$ ls non-existing-file.txt
ls: cannot access 'non-existing-file.txt': No such file or directory
$ echo $?
2

Next, let’s invert its return status:

$ ! ls non-existing-file.txt
ls: cannot access 'non-existing-file.txt': No such file or directory
$ echo $?
0

Now, let’s execute a command that returns a zero status code:

$ echo 'Hello, World'
Hello, World
$ echo $?
0

And invert its return status to non-zero:

$ ! echo 'Hello, World'
Hello, World
$ echo $?
1

Note that there’s a space between the exclamation mark (!) and the command.

4. Executing Commands From the History

Bash maintains the history of the commands executed in the current session. We can use the exclamation mark (!) to execute specific commands from the history.

4.1. Execute the Previous Command

We can use !! to execute the previous command:

$ echo 'Hello, World'
Hello, World
$ !!
echo 'Hello, World'
Hello, World

4.2. Execute the Nth Command

We can use the !n syntax to execute the nth command from the history. In this expression, n represents the command number from history. We can use the history command to list the commands from history:

$ history
...
...
...
124 echo 'Hello, World'
125 history

Let’s execute the 124th command:

$ !124
echo 'Hello, World'
Hello, World

4.3. Execute the Command Starting With a Particular String

We can use !string syntax to execute the command from our history that starts with the given string. Let’s execute the command that starts with echo:

$ !echo
echo 'Hello, World'
Hello, World

5. Referring to Arguments From the History

We can use the exclamation mark (!) to refer to arguments from the previously executed commands.

5.1. Refer to the Nth Argument

We can use !:n to refer to the nth argument from the previously executed command:

$ echo one two three four
one two three four
$ echo !:2
echo two
two

5.2. Refer to the First Argument

We can use !:^ to refer to the first argument from the previously executed command:

$ echo one two three four
one two three four
$ echo !:^
echo one
one

5.3. Refer to the Last Argument

We can use !:$ to refer to the last argument from the previously executed command:

$ echo one two three four
one two three four
$ echo !:$
echo four
four

5.4. Refer to All Arguments

We can use !:* to refer to all arguments from the previously executed command:

$ echo one two three four
one two three four
$ echo !:*
echo one two three four
one two three four

6. Overriding Exit on Failure Behavior

We can configure Bash to stop script execution as soon as there’s a failure in command execution. We can achieve this via enabling the set -e option.

However, sometimes there’s a requirement that certain failures can be ignored. In such cases, we can use the exclamation mark (!) to override exit on failure behavior:

$ cat ignore-failure.sh 
#!/bin/bash
set -e
! ls non-existing-file.txt
echo "Previous command's failure has been ignored."

Let’s execute the script and verify the result:

$ chmod +x ignore-failure.sh
$ ./ignore-failure.sh 
ls: cannot access 'non-existing-file.txt': No such file or directory
Previous command's failure has been ignored.

7. Conclusion

In this tutorial, we discussed various practical examples that show the use of exclamation marks (!) in Bash. We can use these commands in day-to-day life to boost our productivity.