Finding ways to use bash command line history shortcuts
A couple of months ago I wrote about a bunch of command line history shortcuts that Phil had taught me and after recently coming across Peteris Krumins' bash history cheat sheet I thought it’d be interesting to find some real ways to use them.
A few weeks ago I wrote about a UTF-8 byte order mark (BOM) that I wanted to remove from a file I was working on and I realised this evening that there were some other files with the same problem.
The initial command read like this:
awk '{if(NR==1)sub(/^\xef\xbb\xbf/,"");print}' data/Taxonomy/Products.csv > data/Taxonomy/Products.csv.bak
The version of the file without the BOM is data/Taxonomy/Products.csv.bak but I wanted it to be data/Taxonomy/Products.csv so I needed to mv it to that location.
By making use of history expansion we can write this as follows:
mv !$ !!:2
!$ represents the last argument which is data/Taxonomy/Products.csv.bak and !!:2 gets the 2nd argument passed to the last command which in this case is data/Taxonomy/Products.csv.
As you’re typing it will expand to the following:
mv data/Taxonomy/Products.csv.bak data/Taxonomy/Products.csv
One of the things that we do quite frequently is look at the nginx configurations and logs of our different applications which involved doing the following:
$ tail -f /var/log/nginx/site-1-access.log
$ tail -f /var/log/nginx/site-2-access.log
or
$ vi /etc/nginx/sites-enabled/site-1-really-long-name-cause-we-can
$ vi /etc/nginx/sites-enabled/site-2-really-long-name-cause-we-can
Everything except for the file name is the same but typing the up arrow to get the previous command and then manually deleting the file name can end up taking longer than just writing out the whole command again if the site name is long.
Ctrl-w deletes the whole path so that doesn’t help us either.
An alternative is the use the 'h' modifier which "Removes a trailing pathname component, leaving the head."
In this case we could do the following:
$ vi /etc/nginx/sites-enabled/site-1-really-long-name-cause-we-can
$ vi !$:h/site-2-really-long-name-cause-we-can
We still have to type out the whole file name and we don’t get any auto complete help which is a bit annoying.
I realised that on my zsh if I type a space after a history expansion command it expands what I’ve typed to the full paths of everything, which is due to the following key binding:
.oh-my-zsh $ grep -rn "magic-space" *
lib/key-bindings.zsh:20:bindkey ' ' magic-space # also do history expansion on space
We can do the same thing in bash by running the following command:
bind Space:magic-space
Then if I wanted to open that second nginx file I could do the following:
$ vi !$:h # then type a space which will expand it to:
$ vi /etc/nginx/sites-enabled/ # I can then type backspace, then type 'site-2' and tab and open the file
It’s not completely smooth because of the backspace but I think it’s marginally quicker than the other options.
Another one which I mentioned in the first post is the ^original^replacement which will run the previous command but replace the first instance of 'original' with 'replacement'.
With this one it often seems faster to type the up arrow and change what you want manually or retype the command but when doing a grep of a specific folder I think this is faster.
e.g.
$ grep -rn "magic-space" ~/.oh-my-zsh/lib
/Users/mneedham/.oh-my-zsh/lib/key-bindings.zsh:20:bindkey ' ' magic-space # also do history expansion on space
Let’s say I was intrigued about bindkey and wanted to find all the instances of that.
One way to do that would be to type up and then manually go back along the line using Meta-B until I get to 'bind-key' when I can delete that with a few Ctrl-W's but in this case the search/replace approach is quicker:
$ ^magic-space^bindkey
grep -rn "bindkey" ~/.oh-my-zsh/lib
/Users/mneedham/.oh-my-zsh/lib/completion.zsh:24:bindkey -M menuselect '^o' accept-and-infer-next-history
/Users/mneedham/.oh-my-zsh/lib/completion.zsh:71: bindkey "^I" expand-or-complete-with-dots
I’m still looking for other ways to re-use bash history more effectively so let me know any other cool tricks in the comments.
About the author
I'm currently working on short form content at ClickHouse. I publish short 5 minute videos showing how to solve data problems on YouTube @LearnDataWithMark. I previously worked on graph analytics at Neo4j, where I also co-authored the O'Reilly Graph Algorithms Book with Amy Hodler.