Linux Tips - DRYing up the Bash
I just read @jrswab's Linux Terminal article and it's inspired me to create a series of Linux tips articles, this is the first in what I hope will be a long series.
I'm going to keep these posts a bit short so that the volume of content isn't too over whelming. The reason for this is that it's easier to remember new features when you get them in bite-sized pieces. Anyway, the general flavor of these tips is to increase your efficiency at the command line and essentially reduce the amount of repeating yourself.
So, on to the first tip...
Incremental Search
It's kind of funny, I'd been striving for the DRY principal without even knowing that it existed, but essentially it's a principle in software engineering where you try to reduce redundant actions. And one of the redundant actions I see is people whacking the arrow keys to go back through their bash history in order to find a command they did earlier. Please stop doing that when you know the command wasn't done that recently! It's almost painful to watch when you know a better way, instead use Control+R.
Here's how. Let's say you're working on a highly contrived problem where you have some long-and-tedious-to-type directory names. To set up this example, type the following:
mkdir -p long/and/confusing/directory/one
echo hello world > long/and/confusing/directory/one/hello
echo "and some other commands here..."
Now, let's say you did a bunch of other stuff, maybe a find or two, maybe editing some files and then you realize, in your highly-contrived situation, you wanted to run that echo command again, but you don't know how long ago it was you did it, and you can only sort of remember where the file was located. Now, you could sit there like a monkey and whack your up arrow until you eventually get back to the command you want, but really you want to minimize repeating yourself, so instead, type the following:
Control+R
You should see something like the following:
(reverse-i-search)`':
Next, type a part of the command that you can remember, in this case, the word hello
. As you type it, you'll very quickly get a match and see something like this:
(reverse-i-search)`hello': echo hello world > long/and/confusing/directory/one/hello
Every time you press a character it will revise the search and potentially provide a new suggestion because it's incremental (hence the i) and it will search again while you type.
Now you can just hit enter, and it will run the command again, or keep hitting Control+R to cycle through matches. Now, let's say that you don't like any of the suggestions that it has provided and you just want to type a new command, to cancel the search you can use Control+C.
But let's say maybe you don't want to cancel your search, but instead, you'd like to edit that hello world to use proper punctuation and grammar before you execute it again. You can do that, too.
Use either the Escape key or Control+j and then you can edit the command like you would any other command that you're typing in before you press enter and execute it. I know, control J? That's not easy to remember... well, maybe not, but it's a lot easier to reach than the escape key for someone as lazy as I am. Give it a try. Type the following:
Control+R hello Control+J
You should see this:
(reverse-i-search)`hello': echo hello world > long/and/confusing/directory/one/hello
And your cursor should be at the hello
of the file name, so now press Control+J (or Escape) and then you can start editing the command before you run it.
Home and End, and Moving Faster
Now, in the same highly contrived example from the incremental search, you may find yourself in a situation where you're at the end of the command you're typing in and you really want to jump back to the beginning. Now, you could use the Home and End keys, and these are fine if you have a full keyboard or you don't mind wasting the extra time to go hunting for the keys, but you can also use Control+A to jump to the beginning of the line and Control+E to jump to the end of the line. So when you did the Control+R to find that hello command, you could have followed that up with a Control+A to jump back to the beginning of the line and change the "hello world" to a more respectable "Hello, World!". For example, continuing with the reverse incremental search:
Control+R hello
And once you see...
(reverse-i-search)`hello': echo hello world > long/and/confusing/directory/one/hello
Hit Control+J to exit the search.
You should now be sitting with your cursor at the hello in the file name, so jump back to the beginning of the line with Control+A, and now you can move over by a word and fix that hello world
, but hold on, don't go whacking the damn arrow key to move over to the right spot. I just spent all of that time trying to give you a new trick so you wouldn't have to whack those stupid arrow keys, so don't start whacking them now! Instead, hold the control key and then whack the right arrow key once.
Your cursor will move to the right by an entire word and you'll be at the space in front of the h
of hello world
. So now you can fix the hellow world
by putting in some quotes, making the H a capital letter, moving right by two words, putting in the exclamation point, and then finally ending up with the following before hitting enter:
echo "Hello, world!" > long/and/confusing/directory/one/hello
As an added bonus...
This functionality is provided by something called Readline, so any applications that support readline-based tab-completion style functionality may also support Control+R searching.
And I'm going to end here because otherwise the post wont be as bite sized. If you have any questions about this advice or if you have a question about how to make some tedious process shorter, post a reply below and I'll get back to you.
Summary
The arrow keys are fine for moving just a few elements back in your history or moving a few characters on the command line, but use the following commands when they make sense.
Command | Description |
---|---|
Control+A | Jump to beginning of line |
Control+E | Jump to end of line |
Control+R | Start an incremental search (or cycle to next match) |
Control+C | Cancel a search (or other command) |
Control+J | End the search, but keep the match |
Control+Left | Move left a word |
Control+Right | Move right a word |
And, in closing, try not to repeat yourself.