Linux Tips - DRYing up the Bash (incremental search)

in #linux7 years ago (edited)

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.

CommandDescription
Control+AJump to beginning of line
Control+EJump to end of line
Control+RStart an incremental search (or cycle to next match)
Control+CCancel a search (or other command)
Control+JEnd the search, but keep the match
Control+LeftMove left a word
Control+RightMove right a word

And, in closing, try not to repeat yourself.

Sort:  

Actually I'd suggest using zsh with zsh-history-substring-search, which actually is much more convenient.

I generally use bash, but I'll take a look...
Okay, I've installed zsh, I've cloned the repo with the script, and I've updated the .zshrc file to use it... now... how do I use it? I've sourced the .zshrc file but I'm not sure what I should be doing next. Can you give an example of doing some commands and then triggering it?

I remembered that years ago I have learned KSH which is also kinda 'better' than BASH.

That should be really long long ago.

I know, it was like 14 years ago (2003) when I finished high school.

Well, I tried it out but it seems to be the same as in bash... though now I have to try out fish.

yes, fish is awesome; the frustrating thing is that it's bash incompatible.

I used this today manually installing a LEMP stack on a clean server - when I mess up the permissions and only find out later - I did not just bash the up key like usual!

(I came back to read this post, which probably took more time, but I may have learned something!)

I used this today manually installing a LEMP stack on a clean server - when I mess up the permissions and only find out later - I did not just bash the up key like usual!

(I came back to read this post, which probably took more time, but I may have learned something!)

I'm glad it was useful!

Yeah, that's usually how it is, the first few times you do it, it's going to be a bit slower, but once you've got it down it saves tons of time.

After seeing a discussion in steemit.chat I wanted to go back through and add some sources to my old posts. Since this one is too old to edit, I'm leaving them here in a comment.

For most of these I actually used the tried and true method of bashing random keys on the keyboard and seeing the effect. It was tough finding real documentation for it, but the readline manual in section 3 of the man appears to contain a lot of this information, albeit a little less easy to parse. But if you see the section on SEARCHING, it also explains some more cool features, like forward search and restoring the original line.

Further down there's all the stuff I wished I had known about navigating the current command line even faster.

So, even though the readline manual looks like it's only of interest to someone writing code, scroll down, there's tons of good stuff in there.

Seriously though, I might have to read and practice all the cool stuff in there and come back with another article. Sure, it looks like esoteric crap that no mortal would need, but I bet there's some serious time saving stuff in there.