Seven God-Like Bash History Shortcuts You Will Actually Use

Intro

Most guides to bash history shortcuts exhaustively list all of the shortcuts available to you.

The problem I always had with that was that I would use them once, and then glaze over as I tried out all the possibilities. Then I’d move onto my working day and completely forget them, retaining only the well-known !! trick I learned when I first started using bash.

So most never got committed to memory.

Here I outline the shortcuts I actually use every day. When people see me use them they often ask me “what the hell did you do there!?”, conferring God-like status on me with minimal effort or intelligence required.

I recommend using one a day for a week, then moving onto the next one. It’s worth taking your time to get them under your fingers, as the time you save will be significant in the long run.

1) !$ – The ‘Last Argument’ One

If you only take one shortcut from this article, make it this one.

It substitutes in the last argument of the last command into your line.

Consider this scenario:

$ mv /path/to/wrongfile /some/other/place
mv: cannot stat '/path/to/wrongfile': No such file or directory

Ach, I put the wrongfile filename in my command. I should have put rightfile instead.

You might decide to fully re-type the last command, and replace wrongfile with rightfile.

Instead, you can type:

$ mv /path/to/rightfile !$
mv /path/to/rightfile /some/other/place

and the command will work.

There are other ways to achieve the above in bash with shortcuts, but this trick of re-using the last argument of the last command is one I use the most.

https://www.educative.io/courses/master-the-bash-shell

2) !:2 – The ‘nth Argument’ One

Ever done anything like this?

$ tar -cvf afolder afolder.tar
tar: failed to open

Like others, I get the arguments to tar (and ln) wrong more than I would like to admit:

When you mix up arguments like that, you can run:

$ !:0 !:1 !:3 !:2
tar -cvf afolder.tar afolder

and your reputation will be saved.

The last command’s items are zero-indexed, and can be substituted in with the number after the !:.

Obviously, you can also use this to re-use specific arguments from the last command rather than all of them.

3) !:1-$ – The ‘All The Arguments’ One

Imagine you run a command, and realise that the arguments were correct, but

$ grep '(ping|pong)' afile

I wanted to match ping or pong in a file, but I used grep rather than egrep.

I start typing egrep, but I don’t want to re-type the other arguments, so I can use the !:1-$ shortcut to ask for all the arguments to the previous command from the second one (remember they’re zero-indexed) to the last one (represented by the $ sign):

$ egrep !:1-$
egrep '(ping|pong)' afile
ping

You don’t need to pick 1-$, you can pick a subset like 1-2, or 3-9 if you had that many arguments in the previous command.


If you like this, you might like one of my books:
Learn Bash the Hard Way

Learn Git the Hard Way
Learn Terraform the Hard Way

LearnGitBashandTerraformtheHardWay
Buy in a bundle here

4) !-2:$ – The ‘Last But n‘ One

The above shortcuts are great when I know immediately how to correct my last command, but often I run commands after the orignal one which mean that the last command is no longer the one I want to reference.

For example, using the mv example from before, if I follow up my mistake with an ls check of the folder’s contents:

$ mv /path/to/wrongfile /some/other/place
mv: cannot stat '/path/to/wrongfile': No such file or directory
$ ls /path/to/
rightfile

…I can no longer use the !$ shortcut.

In these cases, you can insert a -n: (where n is the number of commands to go back in the history) after the ! to grab the last argument from an older command:

$ mv /path/to/rightfile !-2:$
mv /path/to/rightfile /some/other/place

Again, once learned, you may be surprised at how often you need it.

5) !$:h – The ‘Get Me The Folder’ One

This one looks less promising on the face of it, but is something I use dozens of times daily.

Imagine I run a command like this:

$ tar -cvf system.tar /etc/system
 tar: /etc/system: Cannot stat: No such file or directory
 tar: Error exit delayed from previous errors. 

The first thing I might want to do is go to the /etc folder to see what’s in there and work out what I’ve got wrong.

I can do this at a stroke with:

$ cd !$:h
cd /etc

What this one does is say: get the last argument to the last command (/etc/system), and take off its last filename component, leaving only the /etc.

6) !#:1 – The ‘The Current Line’ One

I spent years occasionally wondering if I could reference an argument on the current line before finally looking it up and learning it. I wish I’d done so well before.

I most commonly use it to make backup files

$ cp /path/to/some/file !#:1.bak
cp /path/to/some/file /path/to/some/file.bak

but once under the fingers it can be a very quick alternative to

7) !!:gs – The ‘Search and Replace’ One

This one searches across the referenced command, and replaces what’s in the first two / characters with what’s in the second two.

Say I want to tell the world that mys key does not work, and outputs f instead.

$ echo my f key doef not work
my f key doef not work

Then I realise that I was just wrongly hitting the f key by accident.

To replace all the fs with ses, I can type:

$ !!:gs/f /s /
echo my s key does not work
my s key does not work

It doesn’t just work on single characters. I can replace words or sentences too:

$ !!:gs/does/did/
echo my s key did not work
my s key did not work

Test

Just to show you how these shortcuts can be combined, can you work out what these toenail clippings will output?

$ ping !#:0:gs/i/o
$ vi /tmp/!:0.txt
$ ls !$:h
$ cd !-2:h
$ touch !$!-3:$ !! !$.txt
$ cat !:1-$

Learn bash interactively in the browser here.


22 thoughts on “Seven God-Like Bash History Shortcuts You Will Actually Use

  1. In #3:
    e!!
    Is much simpler.
    My problem is more often that I type
    gerp find_this file
    Which could be fixed with
    grep !:1-$

  2. BTW – you inspired me to try and understand how to repeat the nth command entered on command line. For example I type ‘ls’ and then accidentally type ‘clear’. !! will retype clear again but I wanted to retype ls instead using a shortcut.
    Bash doesn’t accept ‘:’ so !:2 didn’t work. !-2 did however, thank you!

  3. Nice article! Just another one cool and often used command:
    i.e.:
    !vi opens the last vi command with their arguments.

  4. amazing! Always searched how to get arg-n. thanks :)

    I wondered where was the docs for all this: `man 3 history`.

    I know you wanted to showcase the substition (:gs) thing, but I thought using (bash) expansion would work too in some cases:

    `cp /path/to/some/file{,.bak}`

    Thanks for this article :)

    1. +1 for this comment, almost posted it myself as I am on a brace expansion kick lately… inconspicuously powerful and works in ksh93 (was an AIX admin for a decade)

      !Awesome article

  5. love these, thanks for posting! i also like to use expansion for creating backup files!

    “`
    cp foo{,.bak}
    “`

  6. Nice, but zsh is superior, since you can expand the “!” parts with the tab key, unlike in bash where you cannot see or edit what will be run

    1. There is the histverify shell option in bash, but regrettably it defaults to off AFAIK.
      I wholeheartedly agree that seeing what is about to be executed is paramount in many settings.

  7. I seldom get anything out of these “bash commands you didn’t know” articles, but you’ve got some great tips here. I’m writing several down and sticking them on my terminal for reference.

    A couple additions I’m sure you know.
    1) I use “!*” for “all arguments”. It doesn’t have the flexibility of your approach but it’s faster for my most common need.
    2) I recently started using Alt-. as a substitute for “!$” to get the last argument. It expands the argument on the line, allowing me to modify it if necessary.

    1. Superior clickbait is what I’m going for, so thanks. I was aware of Alt-., but technically that’s not a history shortcut and I didn’t want to confuse.

      !* is a good one, but for some reason it never stays in my cache, but as you say !:1-$ is more flexible and re-usable.

  8. I find most of these too scary without histverify on (and too many systems where I can’t reliably set it to be sure it’s always on…).
    It’s a pity insert-comment (Alt-#) doesn’t expand these either.

    So I guess I’m in the “readline camp” and for 3) it’s “arrow up, Ctrl-a, e, Enter”, for 1) Alt-. and brace expansion for 6) for me.

    This is a very good article to get into ! though for people who can ignore the potential consequences and/or are braver/more confident than me :-)

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.