High-speed Bash

One of my favourite technical presentations I’ve read online has been Hal Pomeranz’s Unix Command-Line Kung Fu, a catalogue of shortcuts and efficient methods of doing very clever things with the Bash shell. None of these are grand arcane secrets, but they’re things that are often forgotten in the course of daily admin work, when you find yourself typing something you needn’t, or pressing up repeatedly to find something you wrote for which you could simply search your command history.

I highly recommend reading the whole thing, as I think even the most experienced shell users will find there are useful tidbits in there that would make their lives easier and their time with the shell more productive, beyond simpler things like tab completion. Here, I’ll recap two of the things I thought were the most simple and useful items in the presentation for general shell usage, and see if I can add a little value to them with reference to the Bash manual.

History with Ctrl+R

For many shell users, finding a command in history means either pressing the up arrow key repeatedly, or perhaps piping a history call through grep. It turns out there’s a much nicer way to do this, using Bash’s built-in history searching functionality; if you press Ctrl+R and start typing a search pattern, the most recent command matching that pattern will automatically be inserted on your current line, at which point you can adapt it as you need, or simply press Enter to run it again. You can keep pressing Ctrl+R to move further back in your history to the next-most recent match. On my shell, if I search through my history for git, I can pull up what I typed for a previous commit:

(reverse-i-search)`git': git commit -am "Pulled up-to-date colors."

This functionality isn’t actually exclusive to Bash; you can establish a history search function in quite a few tools that use GNU Readline, including the MySQL client command line.

You can search forward through history in the same way with Ctrl+S, but it’s likely you’ll have to fix up a couple of terminal annoyances first.

Additionally, if like me you’re a Vim user and you don’t really like having to reach for the arrow keys, or if you’re on a terminal where those keys are broken for whatever reason, you can browse back and forth within your command history with Ctrl+P (previous) and Ctrl+N (next). These are just a few of the Emacs-style shortcuts that GNU Readline provides; check here for a more complete list.

Repeating commands with !!

The last command you ran in Bash can be abbreviated on the next line with two exclamation marks:

$ echo "Testing."
Testing.
$ !!
Testing.

You can use this to simply repeat a command over and over again, although for that you really should be using watch, but more interestingly it turns out this is very handy for building complex pipes in stages. Suppose you were building a pipeline to digest some data generated from a program like netstat, perhaps to determine the top 10 IP addresses that are holding open the most connections to a server. You might be able to build a pipeline like this:

# netstat -ant
# !! | awk '{print $5}'
# !! | sort
# !! | uniq -c
# !! | sort -rn
# !! | sed 10q

Similarly, you can repeat the last argument from the previous command line using !$, which is useful if you’re doing a set of operations on one file, such as checking it out via RCS, editing it, and checking it back in:

$ co -l file.txt
$ vim !$
$ ci -u !$

Or if you happen to want to work on a set of arguments, you can repeat all of the arguments from the previous command using !*:

$ touch a.txt b.txt c.txt
$ rm !*

When you remember to user these three together, they can save you a lot of typing, and will really increase your accuracy because you won’t be at risk of mistyping any of the commands or arguments. Naturally, however, it pays to be careful what you’re running through rm!

4 thoughts on “High-speed Bash

  1. As an alternative to !$, you can use Esc+. (hold escape, press full stop). That places the last argument from previous command at the cursor, ready for editing.

    Do note: If you’ve pushed ‘up’ through history, it might instead take the last argument from the one prior to the one you’ve found in history (though I can’t remember if this is consistent across platforms)

  2. alias rm=”rm -i” #, bro

    Or, less intrusively, “rm -I”, which only prompts once and only if removing recursively or more than three files (prevents most mistakes)

    Note: remember that C stands for Ctrl and M for Meta (aka Alt).

    e.g.: C-M-d (Hold down Ctrl and Alt then type “d”. Shows the desktop in GNOME 2)

    You should also mention Alt-. which inserts the last argument from the previous command (repeat for ante-previous and so on). Handier than !$ in my opinion.

    Also, giving an argument* to Alt-. inserts the nth argument from the previous command. *which you do by either pressing Escape and then inputting a number (works everywhere) or typing the number while holding down Alt, before pressing Alt-. (handier, may not work in some terminals)

    E.g.: $ echo uno dos tres cuatro $ echo one two three four Then typing “A-0 A-. SPC A-2 A-. SPC A-1 A-..” will insert: $ echo two uno Not very impressive with such short arguments, but a tremendous help with long ones.

    Also important is the kill ring, a feature Emacs users will already be familiar with. Killed text goes to a stack and then you can yank (paste) it back. Some ways to kill text: C-k: kill from the cursor to the end of the line C-u: kill from the cursor to the beginning of the line C-w: kill from the beginning of the word at or preceding the cursor (repeating without moving results in a single, longer kill) M-d: same as above, but forward (also chainable with C-w)

    Getting text from the kill ring: C-y: yank last kill M-y (before typing or moving after C-y): substitute yanked text with previous kill, repeat until desired text is found

    Some of these shortcuts also take arguments like explained before.

    The kill ring is preserved between command invocations, so you can kill something, execute a bunch of commands and then yank what you killed earlier.

  3. Pingback: BASH history articles | kossboss

Leave a Reply

Your email address will not be published. Required fields are marked *

You can use Markdown if you want.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>