Advanced Shell Topics: Bang Character


The exclamation point, which is more commonly known as the bang in geek-ish, is another special character for indicating that you'd like to retrive a value from the shell. Probably the most common way that it is used is when you want the last argument on the last line:

  [user@host www]$ ls -l index.html
  -rw-------   1 user     users         687 Nov 27 07:43 index.html
  [user@host www]$ chmod 644 !$
  chmod 644 index.html
  [user@host www]$ ls -l index.html
  -rw-r--r--   1 user     users         687 Nov 27 07:43 index.html
  [user@host www]$

Notice that when I used the bang notation the shell printed out an extra line showing me the full command line that executed. This is for your safety so that you can catch your own mistakes say if you did something like this:

  [user@host www]$ mv backup/* .
  [user@host www]$ rm -fr !$
  rm -fr .
  [user@host www]$

Whoops! I'd recommend against ever using rm or any other destroying command in conjunction with !$.

The bang character can also be used to search and run the last instance of a command. So let's say that you are diagnosing a problem with a webserver and have to restart or reload it every time you make a change.

  [root@host www]# /etc/rc.d/init.d/httpd restart
  Shutting down http:                                        [  OK  ]
  Starting httpd:                                            [  OK  ]
  [root@host www]#

Instead of using the up arrow to go back in through the command history you can use the bang character and enough characters to located the previous instance of the httpd restart command:

 
  [root@host www]# !/etc
  Shutting down http:                                        [  OK  ]
  Starting httpd:                                            [  OK  ]
  [root@host www]#

Please note that this works just like wildcards or regular expressions and will search for the first occurance of what you specified after the bang. So !/etc could possibly match many init script command lines. You should only use this method when you're absolutely sure of what it is going to execute.

I use this nearly every day when I reload the DNS server at the ISP that I work for. The complete command that I use includes running tail -f /var/log/messages before the reload so that we can make sure that any changed zone files loaded ok.

  [user@host www]$ tail -f /var/log/messages & /usr/local/sbin/reload-dns
 (massive snippage of logs)

  [user@host www]$ !tail

So this example shows that the matching will not just match one command, but the whole command line, which is where this becomes most useful I think. If you're unsure of what the last command line that might match in your history will look like, you can use Ctrl-r to do a reverse search.

Ctrl-r will prompt you for a reverse search and as you type in characters it will begin showing you the previously found instance of your search, if you wish to go back further without typing any more letters you can hit Ctrl-r multiple times/P>

[root@host ~]#
(reverse-i-search)`':                                 (Pressing Ctrl-r prompts you)
(reverse-i-search)`t': echo five four three two one   (typing in a t)
(reverse-i-search)`ta': tail -f /var/log/messages     (typing in an a)
(reverse-i-search)`ta': tar zxvf encrypt-0.9.tgz    (Pressing Ctrl-r again searchs back for 'ta' again.)
[root@host ~]# tar zxvf encrypt-0.9.tgz   (Hitting Esc will take back to the command line.)



© 2000 Suso Banderas - suso@suso.org