Saving time by repeating history
- 01 October, 2016 03:31
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: bound to 172.30.0.28 -- renewal in 1568 seconds. Sep 30 15:10:54 ip-172-30-0-28 dhclient: bound to 172.30.0.28 -- renewal in 1459 seconds. Sep 30 15:35:15 ip-172-30-0-28 dhclient: bound to 172.30.0.28 -- renewal in 1705 seconds. Sep 30 16:03:42 ip-172-30-0-28 dhclient: 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 (18.104.22.168) $ !-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: DHCPREQUEST on eth0 to 22.214.171.124 port 67 (xid=0x7e717059) Sep 30 16:03:40 ip-172-33-0-28 dhclient: DHCPACK from 126.96.36.199 (xid=0x7e717059) Sep 30 16:03:42 ip-172-33-0-28 dhclient: bound to 188.8.131.52 -- 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.