Unix tips: Saving time by repeating history

castle
Credit: flickr / Hefin Owen

Getting work done faster on the command line is one of the never changing goals of Unix sysadmins. And one way to do this is to find easy ways to reuse commands that you have entered previously – particularly if those commands are complex or tricky to remember. Some of the ways we do this include putting the commands in scripts and turning them into aliases. Another way is to reissue commands that you have entered recently by pulling them from your command history and reusing them with or without changes.

 

The easiest and most intuitive way to reissue commands is by using the up and down arrows on your keyboard to scroll through previously entered commands. How far back you can scroll will depend on the size of your history buffer. Most people set their history buffers to hold something between 100 and 1,000 commands but some go way beyond that. Hitting the up arrow 732 times might try your patience, but there are are fortunately easy ways to get what you need without wearing out your finger tip! To make this post a little easier to follow, I'm using a modest HISTSIZE setting. You can view your current history queue size using the command shown below

$ echo $HISTSIZE
1000

The easiest thing to do with command history is repeating your previous command. Either pressing the up arrow or typing !! will repeat do that. Most of the time, however, this little trick is not the most useful.

$ date
Fri Sep 30 11:46:06 EDT 2016
$ !!
date
Fri Sep 30 11:46:08 EDT 2016

You can also rerun your previous command but with a change by specifying the old and new strings between circumflex (^) marks like this:

$ du -sk temp
9168    temp
$ ^temp^bin^
du -sk bin
36      bin

This trick can be particularly useful when the command you want to reuse is long and complicated.

You can always press the up arrow on your keyboard multiple times to get to back to previous commands but, if the command you want to reuse was one you entered 1,234 commands ago, it might be easier to use the first part of the command following an exclamation point like this:

# !tail
tail -2 /var/log/messages
Sep 30 15:56:14 ip-172-33-0-28 su: (to root) shs on pts/0
Sep 30 15:57:54 ip-172-33-0-28 su: (to root) shs on pts/0

You can rerun the last cat command by simply typing !cat and the last grep command by typing !grep and the last command you issues through sudo by typing !sudo.

$ !sudo
sudo tail -12 /var/log/messages | grep bound
Sep 30 14:44:44 ip-172-30-0-28 dhclient[1848]: bound to 172.30.0.28 -- renewal in 1568 seconds.
Sep 30 15:10:54 ip-172-30-0-28 dhclient[1848]: bound to 172.30.0.28 -- renewal in 1459 seconds.
Sep 30 15:35:15 ip-172-30-0-28 dhclient[1848]: bound to 172.30.0.28 -- renewal in 1705 seconds.
Sep 30 16:03:42 ip-172-30-0-28 dhclient[1848]: bound to 172.30.0.28 -- renewal in 1712 seconds.

How much you need to type will depend on how many commands you've typed since the target command and how unique the command is. If the command you want to reuse is one you issued a couple days ago, you will probably need to reenter more of it to make sure you repeat the correct command.

You can also reissue any command that's in your history buffer by typing ! followed by the command number.

$ history
    2  echo 4
    3  echo 5
    4  echo 6
    5  echo 7
    6  echo 8
    7  echo 9
    8  echo 10
    9  history
   10  vi .bashrc
   11  history
$ !7
echo 9
9

While !! makes it easy to repeat your previous command, you can also rerun previous commands by specifying how far back into your history you want to go. The command preceding your last command would be rerun by entering !-2.

$ uptime
 12:06:03 up 418 days,  2:36,  1 user,  load average: 0.00, 0.01, 0.05
$ who
ec2-user pts/0        2016-09-30 12:02 (192.161.76.108)
$ !-2
uptime
 12:06:11 up 418 days,  2:36,  1 user,  load average: 0.00, 0.01, 0.05

If you can remember what command you typed 11, 123, or some other number of commands ago, you're a lot better at that than I. For most of us, it's probably a lot easier to use history to find the command you want to reuse and then running at again with its command number.

$ history | grep sudo
   12  sudo tail -4 /var/log/messages
   13  history | grep sudo
$ !12
sudo tail -4 /var/log/messages
Sep 30 15:57:54 ip-172-33-0-28 su: (to root) shs on pts/0
Sep 30 16:03:40 ip-172-33-0-28 dhclient[1848]: DHCPREQUEST on eth0 to 172.33.0.1 port 67 (xid=0x7e717059)
Sep 30 16:03:40 ip-172-33-0-28 dhclient[1848]: DHCPACK from 172.33.0.1 (xid=0x7e717059)
Sep 30 16:03:42 ip-172-33-0-28 dhclient[1848]: bound to 172.33.0.28 -- renewal in 1712 seconds.

You can also rerun the last command that contained a particular string – maybe a file name or a username – by preceding that string with !?.

$ !?messages
sudo tail -12 /var/log/messages | grep bound

That particular trick can come in very handy when you want to issue multiple commands against the same file, for example.

The syntax for reusing only the first argument from a previous command is a bit tricky, but here'a an example. In this command sequence, we run a command and then use a history trick to reuse just the first argument in another command:

$ touch file1 file2 file3
$ cat !touch:^
cat file1
a:one:1
b:two:2
c:three:3

As you can see, we put the string you are looking for between the ! and :^.

We can do something similar for 2nd, 3rd, etc. arguments by using the syntx !command:# where # is the number of the argument you want to reuse.

$ touch file1 file2 file3
$ tail !touch:2
tail file2
a:one:1
b:two:2
c:three:3
d:four:4
e:five:5
$ tail !touch:3
tail file3
this file is empty

Saving significant time by reusing commands through history tricks is great but you have to remember some syntax which is anything but obvious.

This article is published as part of the IDG Contributor Network. Want to Join?

To express your thoughts on Computerworld content, visit Computerworld's Facebook page, LinkedIn page and Twitter stream.
Related:
Windows 10 annoyances and solutions
Shop Tech Products at Amazon
Notice to our Readers
We're now using social media to take your comments and feedback. Learn more about this here.