Skip to main content

Bash bang commands: A must-know trick for the Linux command line

Your bash history maintains a record of the commands you've entered. Here's how to make good use of that record.
Image
Hammer

Ever forget to issue sudo before a command? Ever had to repeat a whole command because you had a typo? Have you ever thought it would be nice to have shortcuts to repeat your previous commands? If this sounds like you, I have something to share. In this article, I will show you how to use bash bang (!) commands, which make it easy to repeat commands and fix errors.

Command repeat basics

Bash provides access to the list of commands you previously issued, which is known as your command history. The value of the HISTSIZE variable sets the number of commands that are saved in your history list. By default, this value is 500. These previously issued commands (known as your history list) are stored in your history file. Its default location is ~/.bash_history, and this location is stored in the shell variable HISTFILE.

Under the hood, bang (!) commands introduce commands from your bash history list into the input stream. This feature makes it easy to repeat commands, substitute text, manipulate arguments, and fix typos in your previous commands quickly.

Command repeat examples

Here are some examples of what you can do with bash bang.

Repeat the last command matching a string’s beginning

The bang (!) followed by the first character (or string) matching the command you want to run will repeat the most recent instance of that command:

$ ls
dir  dir1  dir2  file  file1  file2  hello.txt

$ !l
ls 
dir  dir1  dir2  file  file1  file2  hello.txt

$ !ls
ls 
dir  dir1  dir2  file  file1  file2  hello.txt

Repeat the last command matching anywhere in a string

The !?<string> format does the same as the above, but <string> doesn’t have to be at the beginning of the command:

$ cat hello.txt 
Hello world ..!
$ !?hello.txt
cat hello.txt 
Hello world ..!

Repeat the nth command from your history

Repeating the nth command from your bash history (counting down from the top) is as simple as using a bang with the number in question:

!10

Repeat the nth command from your last history entry

Repeating the nth command from your bash history (counting up from the bottom) is as simple as using a bang with a minus and the number in question:

!-10

Repeat the last command

If there is one bang command that I use all the time, it would be !!. The bang-bang (!!) command repeats the last command from the history list, behaving the same as !-1 :

$ cat hello.txt 
Hello world ..!
$ !!
cat hello.txt 
Hello world ..!

Bang-bang (!!) is useful when you need to repeat the previous command, or if you need to prefix sudo, or pipe output:

$ yum update
Loaded plugins: priorities, update-motd, upgrade-helper
You need to be root to perform this command.
$ sudo !!
sudo yum update
Loaded plugins: priorities, update-motd, upgrade-helper
$ ls
dir  dir1  dir2  file  file1  file2  hello.txt
$ !! | grep file
ls | grep file
file
file1
file2
$ 

Repeat but substitute a string

Often I issue long commands and reissue them with different switches. Or, I need to reissue a command because there was a typo in my previous command. String substitution lets me do this without retyping the whole long command.

There are two ways we can achieve this result. One is by using:

!!:s^<old>^<new>

This structure substitutes a string for the previous command:

$ ls /etc/httpd/conf.d
autoindex.conf  notrace.conf  php.conf  php-conf.7.2  README  userdir.conf  welcome.conf
$ !!:s^conf.d^conf
ls /etc/httpd/conf
httpd.conf  magic

You can even do the same with !<string>:s^<old>^<new>:

$ !l:s^conf^conf.d
ls /etc/httpd/conf.d
autoindex.conf  notrace.conf  php.conf  php-conf.7.2  README  userdir.conf  welcome.conf

This option is useful when you need to do string substitution for a command that was not the most recent.

The other way we can achieve this result is through the structure ^<old>^<new>. This format substitutes strings for the most recent command, similar to !!:s^<old>^<new>:

$ cd /etc/httpd/conf.d
/etc/httpd/conf.d 
/etc/httpd/conf.d $ ^conf.d^conf
cd /etc/httpd/conf
/etc/httpd/conf $ 

Repeat command arguments

Often, we use the same arguments from a preceding command. If you have a long argument, you probably want to repeat it with the next command. Let’s look at some bash bang commands that can do this for us.

First, the format !:n repeats the nth argument from the preceding command, with 0 being the command itself:

~/project $ ls -a -l 
total 32
drwxrwxr-x  7 user user 4096 Sep  9 20:30 .
drwx------ 16 user user 4096 Sep  9 20:10 ..
drwxrwxr-x  2 user user 4096 Sep  9 16:02 dir
drwxrwxr-x  2 user user 4096 Sep  9 16:02 dir1
drwxrwxr-x  2 user user 4096 Sep  9 16:02 dir2
drwxrwxr-x  2 user user 4096 Sep  9 20:30 dir3
-rw-rw-r--  1 user user    0 Sep  9 16:02 file
-rw-rw-r--  1 user user    0 Sep  5 16:07 .file
-rw-rw-r--  1 user user    0 Sep  9 16:01 file1
-rw-rw-r--  1 user user    0 Sep  9 16:01 file2
-rw-rw-r--  1 user user   16 Sep  9 16:03 hello.txt
drwxrwxr-x  2 user user 4096 Sep  5 16:08 .hidden_dir
-rw-rw-r--  1 user user    0 Sep  5 16:08 .hidden_file
~/project $ ls !:1
ls -a
.  ..  dir  dir1  dir2  dir3  file  .file  file1  file2  hello.txt  .hidden_dir  .hidden_file

Second, !!:$ repeats the last argument from the preceding command. You can shorten this command to !$ and $_:

project $ mkdir dir3
project $ cd !$
cd dir3
project/dir3 $ 

You might ask, "What if I want to use this technique with a command I issued previously, but not the most recent one?" You can do so with bang commands, using either:

!<command you've issued previously >:$ 

$ mkdir -p hello/test1/test2
$ ls !mkdir:$
ls hello/test1/test2

or:

!<command you've issued previously >:n

$ ls !mk:2
ls hello/test1/test2

Sometimes you might want to print out the command, but don’t want it executed. You can accomplish this task with !:p:

~/project $ cat hello.txt 
Hello world ..!
~/project $ !:p
cat hello.txt 
~/project $ 

In fact, you can print out any command in your history list without executing it. Just issue one of the following:

$ !<command>:p

$ !mkdir:p
mkdir -p hello/test1/test2

$ !<string>:p

$ !su:p
sudo yum check-update
$ !mk:p
mkdir -p hello/test1/test2

Recall commands with reverse-i-search

As a sysadmin, you probably issue hundreds of commands every day. You might have a hard time recalling some commands or recalling part of one. Here is another option for finding the one you need.

(reverse-i-search)`<search string>’: <output> (reverse-i-search)`yu': sudo yum check-update
(reverse-i-search)`cd': cd /etc

CTRL+R activates reverse-i-search, which provides a nice search area, giving you an easier way to navigate through your history. 

Conclusion

These are useful bash bang (!) commands that every sysadmin should be familiar with. These commands save tons of time and give you the ability to quickly fix command errors. Read more about bash in its man page, with the command man bash.

[Want to try out Red Hat Enterprise Linux? Download it now for free.]

Topics:   Linux   Command line utilities  
Author’s photo

Keerthi Chinthaguntla

Keerthi is aspiring Cloud, DevOps engineer, he has been working with Windows and Linux systems. He believes in continuous learning (CL) and continuous sharing (CS), on his way building his very own CL CS pipeline. When he is not playing in the CLI, you will find him playing Cricket.  More about me

Try Red Hat Enterprise Linux

Download it at no charge from the Red Hat Developer program.