The GNU Bourne Again SHell has become the ubiquitous shell in all *nix installations far and wide. While there are other contenders in this field, playing keystroke golf by typing smarter and not harder will naturally evolve into muscle memory and reduce the path from what you want to what you get.
Over time, you’ll make less mistakes and spend less time in the console.
Let’s dive right in.
The popular GNU readline library is used by many interactive shells. The default bindings are similar to those of Emacs (the notation is C- for Ctrl, and M- for Meta (usually Esc or Alt)):
C-l: refresh or clear lineC-a: go to beginning of lineC-e: go to end of lineC-k: kill/delete to the end of the lineC-u: kill/delete to the beginning of the line (note: not in emacs)C-d: delete (not kill) next letterM-d: kill/delete next wordC-_: undoReadline also has its own kill ring, known to many as a clipboard, but provides additional functionality where you can kill (cut) and yank (paste) multiple strings.
A common idiom I use is “stashing” (à la git) a command into the kill ring, by using C-u to kill and C-y to yank.
For example, I might have gotten this far typing out a command:
$ ls -al /awesome/but/so/much/typing
When I realize I need to do something else, so I hit C-u to kill to the beginning of the line:
$
Then I go about my business:
$ df -h
...
$ cat /etc/fstab
...
And now back at a blank prompt,
$
I can use C-y to restore the original line:
$ ls -al /awesome/but/so/much/typing
Of course, if you kill anything else in the interim, between the first and the last step, that will affect the final paste. (Hint: you can use M-y repeatedly, after a C-y, to rotate through what you’ve killed.)
For bonus points, a subset of these keybindings are available across Mac OS X text fields, notably C-a, C-e, C-k and C-y. jwz had a fun exposé on Apple breaking C-y not too long ago.
If you have a program that doesn’t have readline bindings, there’s a cool program called rlwrap which magically gives you history and the power of readline. It’s largely available via your local friendly package manager.
For example, back in the days of Redis 1.x, the CLI was more primitive, but a simple launching via
$ rlwrap redis-cli
gave you all the powers you needed.
Most people know that the vertical arrow keys (up and down) can be used to navigate history. For the previous command of the current session, hit up. Gone too far back in time? Use down to trace back your steps.
Even better, use C-r for reverse history search, which is not limited to just your current session. Emacs users should find this particularly familiar (isearch-reverse), except without all the highlighting and jumping around you would expect from an editor.
To search backwards in history, type C-r and then a string of letters to search from your shell history. To continue searching the same string of letters, hit C-r again. To cancel, C-c. If at any point no matches are found, you’ll get an alarm (visual or audio beep). Once your satisfied, hit enter.
It takes some getting used to, but you can try the following in a test directory:
$ touch foo bar
$ ls foo
foo
$ ls bar
bar
$
At this point, typing C-r will yield
(reverse-i-search)`':
Typing just ”ls,” you should end up with
(reverse-i-search)`ls': ls bar
Hitting C-r once again, it will search further and display to
(reverse-i-search)`ls': ls foo
At this point, you may hit enter to run the command or, alternatively, a keystroke like C-e to the end of the line to see the whole command.
$ ls bar
bar
Just like that, it’s like you typed out the whole command by yourself.
On a related note, Bash has a short memory of sorts. By default, the HISTSIZE variable is set to 500 lines. Edit your ~/.bash_profile or ~/.profile to make it much longer:
export HISTSIZE=999999
If you ever accidentally need to scrub something from your own history, like an errant password entered as a command, just edit ~/.bash_history.
Even more esoteric, but extremely useful is the yank-last-arg command in readline, which is M-. or M-_ (dot or underscore, respectively). This takes the last argument from your last executed command, and appends it to your cursor.
For example, say you had to type out a super long filename:
$ ls /super/cali/fragilistic/expiali/docious
/super/cali/fragilistic/expiali/docious
Now if you decide to edit the file
$ emacs
but instead of typing out the whole filename again, summon M-.
$ emacs /super/cali/fragilistic/expiali/docious
Magical!
The bang operator (!) can also be used to execute the last matching command. From our last example, immediately using the bang with ls will result in running the last ls command:
$ !ls
ls bar
bar
I use this with more innocuous commands like ls, and hardly ever with rm or even cat (I tend to append or write files with it).
The double bang (!!) is shorthand for the last command, which people have suggested pairing with sudo if one accidentally tries running a command with insufficient privileges.
$ make me a sandwich
make: *** No rule to make target `me`. Stop.
$ sudo !!
sudo make me a sandwich
You have new mail.
There is a whole set of bang operators relating to last commands or arguments, but I use these sparingly as I like to see my commands before I run them.
Many are familiar with the tilde notation for one’s home directory:
$ cd ~/treehouse
$ pwd
/home/jerry/treehouse
It also works as a prefix for other users:
$ cd ~bob/treehouse
-bash: cd: /home/bob/treehouse: Permission denied
Not cool, Bob.
Anyhow, this tends to be more useful as root, and even has tab completion powers in Bash.
Many swear by Zsh, which doesn’t shy away from putting the “interactive” in interactive prompt, and is highly customizable. For one, it excels in tab completion, e.g. if SSH keys are setup correctly, one can tab complete remote paths! I used it for a few months after the incessant praises by a friend.
Ultimately, I reverted to Bash by switching to a new computer, and too lazy to port over my zsh dotfiles, I never looked back. However, those interested in zsh may want to take a look at oh-my-zsh, or heavily borrow from your favorite zsh hacker’s dotfiles.
While I’ve focused on more built-in features of bash rather than common Linux utilities, the Stack Overflow question, “What is your single most favorite command-line trick using Bash?,” has a great set of tips.
Your mileage may vary. If you commute from the suburbs in a car twice a day, five times a week, driving a gas guzzler can be expensive. If you only get into your vehicle when you need to run to the grocery, maybe it doesn’t matter so much what you drive. If you are confused by this metaphor that just came out of left field, I can’t blame you.
Such a large portion of computing is identifying repeating, slow, redundant, inefficient, sisyphean tasks, and optimizing them away. GPUs specialize in performing specific calculations in hardware. Compilers unroll loops and inline functions to make code faster. Virtual machines detect what’s running hot and makes adjustments on the fly.
So why not do this with our keyboards? ∪