My Favorite Bash Substitution Tricks

August 01, 2009

Here’s a few tricks that I often use on the command line to save time. They take advantage of some variables that the bash shell uses to store various aspects of your history.

Repeating the last command with !!

Sometimes I run a command that requires sudo access, but forget the sudo. This is a great opportunity to use !! which holds the last command you ran.


$ tail /var/log/mail.log
tail: cannot open `/var/log/mail.log' for reading: Permission denied
$ sudo !!
sudo tail /var/log/mail.log
# output of command

The last argument of the last command using !$

Sometimes it’s handy to be able to reference the last argument of your last command. This can make certain operations safer, by preventing a fat fingered typo from deleting important files.


$ ls *.log
a.log  b.log
$ rm -v !$
removed `a.log'
removed `b.log'

Similarly you can use !* to reference all of the last commands’ arguments.


$ touch a.log b.log
$ rm -v !*
rm -v a.log b.log
removed `a.log'
removed `b.log'

Correcting mistakes with ^^

This is a nifty trick that performs a substitution on your last command. It’s great for correcting typos, or running similar commands back to back. It looks for a match with whatever is after the first carrot, and replaces it with whatever is after the second.


$ cmhod a+x my_script.sh 
-bash: cmhod: command not found
$ ^mh^hm
chmod a+x my_script.sh 

I use this one all the time doing rails development if I make a mistake on a script/generate command.


$ script/generate model Animal species:string sex:string birthday:date
      exists  app/models/
      exists  test/unit/
      exists  test/fixtures/
      create  app/models/animal.rb
      create  test/unit/animal_test.rb
      create  test/fixtures/animals.yml
      create  db/migrate
      create  db/migrate/20090801180754_create_animals.rb

$ ^generate^destroy
script/destroy model Animal species:string sex:string birthday:date
    notempty  db/migrate
    notempty  db
          rm  db/migrate/20090801180754_create_animals.rb
          rm  test/fixtures/animals.yml
          rm  test/unit/animal_test.rb
          rm  app/models/animal.rb
       rmdir  test/fixtures
    notempty  test
       rmdir  test/unit
    notempty  test
       rmdir  app/models
    notempty  app

$ ^destroy ^generate rspec_
script/generate rspec_model Animal species:string sex:string birthday:date
      create  app/models/
      create  spec/models/
      create  spec/fixtures/
      create  app/models/animal.rb
      create  spec/models/animal_spec.rb
      create  spec/fixtures/animals.yml
      create  db/migrate
      create  db/migrate/20090801180937_create_animals.rb

Hope someone else finds these as handy as I do.

Comments

  1. Sam
    Sam August 02, 2009 @ 11:20 AM

    One more tip:

    You can also echo a specific number of arguments off the end of the last command using !:n*, where n is the number of the first argument to echo. For example:

    $ touch 1.log 2.log 3.log 4.log 5.log
    
    $ rm -v !:3*
    rm -v 3.log 4.log 5.log
    3.log
    4.log
    5.log
    

    I don’t use this one too much in practice but it could come in handy in certain situations.

  2. Kirsten
    Kirsten August 03, 2009 @ 05:15 PM

    Thanks Sam, I didn’t know about !* and the ^^ substitution, those will be useful!