Hacker News new | past | comments | ask | show | jobs | submit login
Advancing in the Bash Shell (samrowe.com)
501 points by yarapavan on Sept 13, 2016 | hide | past | web | favorite | 149 comments

I don't use !!, or !$, because I prefer to see what command is being executed before I press enter. For the same reason, I will never use !word. But that's not a problem, because as others have noted bash makes it easy to not have to fall back to these.

Alt-. will generally add the prior last argument into the current command, and repeated presses will cycle through previous commands.

Ctrl-r will dynamically update to show you the prior command matched as you start typing afterwards, so you can confirm it's correct.

Both are essential if you want to reuse prior commands but either can't trust that you were the last person using the shell, or don't want a typo to ruin your day, and possibly many other people's day as well. That is, if you're a sysadmin using the automatic variants, I don't want you anywhere near systems I rely on, I want you far away. Perhaps working for a competitor.

>I don't use !!, or !$, because I prefer to see what command is being executed before I press enter.

I use zsh (with oh-my-zsh) and when I type e.g. "sudo !!" and press enter, it doesn't execute the command, instead it expands the !!. Another enter will then actually execute it.

I believe it's default behavior for oh-my-zsh. At least, I don't recall manually changing this.

This is achieved in bash by shopt -s histverify

I don't use history expansions, though, so YMMV

In zsh you can type !!<tab> and it will auto-expand the line for you. I find histverify to be kind of annoying so I don't use it.

How so?

I think by default in vanilla zsh, will expand something like 'sudo !!' by hitting tab after the second bang.

You are correct.

Same behavior on zsh with prezto.

If you don't want to rely on the "histverify" option being enabled, you can get a similar effect by appending ":p" to the history reference, e.g.

    sudo !!:p
which tells bash to do the history expansion, but print the result and add it to the command line history, instead of actually running it. If the command looks correct, it's only two more keystrokes (up-arrow, enter) to run it for real.

That feels dangerous. For example, on Swedish keyboards the character ; is one key away from :

I've got 'bind Space:magic-space' in my .bashrc, which performs history expansion after you hit space, maybe that partially helps. I guess there's friction if the expanded command isn't the one you want, which the interactive methods are better at dealing with.

I use this bash feature also.

I think this not just "partially helps", I think it completely addresses the problem described by the above commenter. Perhaps s/he is not aware of this feature.

In addition to all the other methods which have been mentioned bash has a function called history-expand-line which will expand the history inline. That allows you to even keep editing it before you hit enter. By default it's bound to the terrible M-^ (Alt-^) which might explain why nobody knows about it.

history-expand-line is documented in: https://www.gnu.org/software/bash/manual/html_node/Miscellan...

Is it the same as Ctrl-Alt-e ?

Sure is, it appears to do the same thing

> I don't use !!, or !$, because I prefer to see what command is being executed before I press enter.

shopt -s histverify

histreedit is also pretty useful especially when a substitution fails.

  shopt -s histreedit
If set, and readline is being used, a user is given the opportunity to re-edit a failed history substitution.

Until you log in to a different machine where that isn't set in the .bashrc / .profile .

> I don't use !!

Not even "sudo !!" ?

You can see the command you just typed in the line above, and you just forgot to add sudo to it.

Nope. It's easier to not have to make a decision about when to use !! or not, so I just don't. Up, Ctrl-a, "sudo ", Enter.

Another way of putting it is that I'll gladly press another 2-3 keys if it prevents a class or errors and also reduces the number of special bash instructions I have to keep in memory. !! isn't even in my repertoire, but I don't feel its loss.

per your own recommendations: "sudo ", alt-. would be one less keystroke

yes, but it's not equivalent, as Alt-. only repeats the last argument.

For example, say you want to run "chown root:root foo". Alt-. gets you "foo", not the entire command, and "sudo foo" isn't useful,and in some cases could do something else entirely. For example, with the command "service foo restart", you would end up with "sudo restart" (which while it doesn't execute right away, is exactly what I'm guarding against).

M-. takes the last argument by default, but it can grab other arguments by using numeric arguments (M-1, M-2, etc.) that usually has the effect of repeating the next command.

Unlike Emacs, M-1 etc. can't be typed as C-u 1 etc.

Atl-. will cycle through the n-th argument, which is not the same as repeating entire last command with all arguments as up-arrow or !! do:

  $ yum install bash-completion
  Error: This command has to be run under the root user.
  $ sudo <Alt-.>
  $ sudo bash-completion

good point, so not equivalent after all

A lot of times it is also about muscle memory. For example although I also use alt+. a lot (although not as often as ctrl+alt+.), for adding sudo my brain reverts to up, ctrl+a, sudo simply because I was doing those long before I learnt about Alt+.

I would never get the habit of using !! with sudo. I want to read what I do, before doing root commands... (Alt-. is possible, I guess. Maybe.)

But I'm an epic coward that even looks both to the left and the right before crossing a street. :-)

In addition to never use `sudo !!`, on systems that I use, the sudo is aliased to the following shell script:


    echo -n "Are you SURE you dumbass? [N/y] " >/dev/stderr
    read -n 1
    if [ "$REPLY" = "y" ]; then
      echo >/dev/stderr
      exec /usr/bin/sudo "$@"
      exec echo -e "\n:-)" >/dev/stderr
That way even if I already typed my password, I systematically get asked if I'm sure I want to execute the command.

control-p, control-a, 'sudo ' return.

I think I'm pretty proficient as a basher, but I also never use the bang, nor do I use the 'history' bit. Didn't know about alt-. tho, that's handy.

I could toss 'control-k' for 'delete to end of line' that hasn't been mentioned. And of course control-P/N for previous/next commands (or arrows obviously).

Don't forget about C-e for end of line and C-d for delete character forward. C-f and C-b make more sense to learn if you have regularly use their whole word variants Meta-f and Metals (alt f/b). Congrats, you know the emacs movement keys.

With zsh, you can tab-expand history… expansion. (Despite this, I also still prefer up-arrow and ^R, since it’s usually faster to ^A and Alt-B/F than to figure out the right way to reference history.)

> I don't use !!, or !$

Neither do I, intentionally at least.

This week I encountered a very bizarre problem when running GHCi (a Haskell REPL), invoked from bash in an Emacs "shell" buffer.

In Haskell, "!!" is a function for getting an element from a list, e.g.

    > let myList = ["a", "b", "c"]
    > (myList !! 1, myList !! 2)
This would normally return the pair ("b", "c"), which GHCi prints to the screen. However, for some reason it was performing bash-like subtitution, giving me (on subsequent retries):

    parse error on input 'let'

    (myList (myList !! 1, myList !! 2) 1, myList (myList !! 1, myList !! 2) 2)

    (myList (myList (myList !! 1, myList !! 2) 1, myList (myList !! 1, myList !! 2) 2) 1, myList (myList (myList !! 1, myList !! 2) 1, myList (myList !! 1, myList !! 2) 2) 2)
and so on exponentially!

Enacs can be set to handle history substitution itself in various ways (the idea being that it can record an accurate history even when your shell can't). There's an option to configure if and when it does this, which you may want to set to never.

The !! is the reason I don't do git commit -m anymore. git commit -m "Stupid!!" gets turned into git commit -m "Stupidgit add file.c"

You can avoid that by using single quotes

> I prefer to see what command is being executed before I press enter

On a similar note, I always get nervous when using "rm -rf", since the path is written in big-endian order, so an accidental nudge halfway through typing can cause something like

    rm -rf ~/Pictures/Scans/NeedConverting/*
To become

    rm -rf ~

One simple way to avoid something catastrophic:

rm -rfi

lets you get an interactive mode so you can confirm what's happening before it gets erased.

Interesting - I use these so routinely it's unconscious, never had a problem. Though I suppose if I'm doing something remotely risky I'll not use them - though I'm not aware of doing that.

The class of shortcuts I love is:

[command] !:1-$

which copies the arguments to the previous command to this one. Or:


which copies the fourth argument.

Once those were under my fingers my fellow architects were astounded.

!* is equivalent but shorter.

!! expands the command after you type enter first...

It expands and then immediately executes, at least in bash by default.

depends on your histverify setting for 'shopt' do a

shopt -s histverify


shopt -u histverify

and then add whatever you prefer (-s probably) to your bashrc

For a personal system, that's fine. For the situation where you are a sysadmin and are jumping onto one of possibly hundreds of systems, I prefer not to rely on a behavior that is specifically made more safe (implying it is less safe as it exists by default) by active configuration. In that situation, it's much easier to just not use the less safe version in favor of the safer version if not too burdensome, and both exist.

...otoh, if you are a sysadmin managing possibly hundreds of systems, you shouldn't be 'jumping onto' any one of them at all these days ! You ought to be using fabric, chef, puppet, ansible ...etc ...Ha ha, only serious ;-)

Sure, those reduce the instances you'll need a shell on a box, but they can't eliminate them. Sometimes you just need to see what's going on on that box, run top, see why there's a few thousand messages in the mail spool ad coax them through, figure out why SQL isn't responding or keeps dying, etc, etc.

I virtually never use !! any more. Instead I just type control-r followed by a portion of the command in my history that I'm interested in.

That's a much more interactive way of getting to the command I want, and if the first match isn't what I want I can either keep typing more of the command or type control-r for the next match. I can also type control-s to go to the previous match. For that last trick to work, you need to do something like this first: stty stop ""

Granted, I use zsh, but I think it works pretty much the same in bash.

Another trick I really like, which I've only used in zsh, but which might exist in bash too (since bash and zsh have so much feature parity these days) is to bind a keystroke to "insert-last-word". When this keystroke is hit, it appends the last argument of the previous command to the end of the current line, further typing of this same keystroke will remove the appended argument and instead append the last argument of the previous command, and so on. I use this all the time and therefore never have to type !$

And my favorite shell trick of all time: set -o vi

Agreed, but even nicer than control-r are the readline functions `history-search-backward` and `history-search-forward`.

Personally I bind them to up/down which on OS X at least involves:

  # Put this in some file like ~/.readline-bindings
  "\e[A": history-search-backward
  "\e[B": history-search-forward

  # And this in your ~/.bashrc or ~/.zshrc
  bind -f ~/.readline-bindings
That way if you haven't typed any input it behaves like normal up (previous command), but if you've typed some characters it only retrieves matching commands.


Just curious since I don't use a mac, doesn't writing the mappings to .inputrc work? IIRC, putting your readline bindings there makes it available for all readline enabled prompts, not just bash ie: Python, pgsql, mysql,.. Etc

Yes I think that's a better approach, thanks. I don't know why I started using `bind` in my shell config.

Mapping these to Up/Down arrows (instead of PgUp-PdDn) is the best idea EVER !!!

Is there a way to make this work with `set -o vi`? So I can use j/k to browse the history this way?

>Granted, I use zsh, but I think it works pretty much the same in bash.

I also use zsh and I don't even use ctrl+r anymore. I just type a portion of the command I remember and hit the up arrow key. Almost always the command I want is only one to three arrow keys away. zsh matches partial commands really well.

Bash has similar commands available to move up and down by matching commands. However, I find such modal behavior of up/down confusing; I prefer to have up and down always move by one command, and use C-r for reverse isearch.

Agreed, but this only works if you know you are right about the beginning of the command. Ctrl-R is still the best way I know to search for a command that I may not be sure about the first letters of.

I like the incremental searching that using control-r lets you do. That can come in really handy when I don't remember precisely what the command I want is.

I can start typing and then type more once I see some results to hone in more precisely to what I want, or even backspace over some of what I've typed and type some more without having to start all over again.

Also, using control-r instead of the arrow keys doesn't force me to move my wrists and lets me keep my fingers mostly on the home row. I try to use the arrow keys as little as possible.

Not moving your hand away from the home row is a good point!

Now I gotta retrain my muscle memory :)

You should be able to use ctrl-p/n for arrow up/down. That keeps your hand on the homerow. Forget about arrow keys (especially on a typical mac keyboard).

Ctrl-p/n are a quicker way to go up and down the history.

An interesting "extension" of C-r with zsh is to add pattern search:

bindkey '^r' history-incremental-pattern-search-backward

When you remember parts of the commands, you can do "C-r" then "echo*something".

fzf [0] works pretty well for this.

[0] https://github.com/junegunn/fzf

Is there any way to force the installer to compile from source rather than downloading a binary?

I'm a little wary of precompiled binaries.

There's a Makefile in the src directory, seems like you can run "make release" to compile from source.

Do you also validate the whole source code, including running it through static analysis, before compiling it?

Agreed. I guess everything is subjective, but when I read the article state:

> While the [ctrl-r] method is more powerful, when doing some redundant task, it’s much easier to remember !22 than it is to muck with ctrl-r type searches or even the arrow keys.


> When this keystroke is hit, it appends the last argument of the previous command to the end of the current line

There's `Meta-_` to insert the previous last word, but you cannot cycle with the previous words--it inserts the last word of the previous commands. You can give it a count, though (with Meta+nums).

I wonder how many people know a few of these (like ctrl-a and ctrl-e and other navigation commands) come not from bash per se but from readline[0]. It isn't a surprise, then, that these mirror emacs commands. For example, one I use often is ctrl-k to kill to the end of a line...and, yes, just like emacs, you can yank it back with ctrl-y too :)...I often do this if I type out a huge command, forget that I needed to type another before, so I use that to "save" commands before execution. That is, it's essentially cheap copy and paste on the commandline.

Cherry on top? These work on other readline using tools! They work in the interactive repl's like python, node, irb, ghcim the exact same shortcuts... it makes working with repl's much more pleasant for me.

[0] https://cnswww.cns.cwru.edu/php/chet/readline/rltop.html [1] quick note, node might use a readline like but it doesn't support yanking (pasting) unfortunately.

I consider this misinformation and makes my blood boil. I feel like the author learn partial information and decided to write a blog about without researching further...

ctrl-R is not bash, it's GNU readline.


If you are going to use command line, than absolutely you should use command history editing, but why limiting yourself to a few commands learned through osmosis or haphazardly rather than use a full editor? Why use C-r to search backwards, but not M-backspace to delete an entire word?

When I explain this, people usually argue that "there are two many weird commands to learn, and I only need the few I know". The same type of people often go on a rant about how much vim is so much better than emacs.

There are not weird command to learn, none, zero!

Use your preferred editor! You already know it, you already know all those commands, and if you don't buy a book and learn them! You know and like emacs? Great, that's the default in readline. Go ahead C-r, C-backspace, C-a, C-e, M-f all you need. You already know all of those.

But you don't like emacs, or don't even know that it exists beside the fact that it's something fun to shit on? You think you're a big shot because you know vim really well? Not an issue, type the magic command "set -o vi" and you are now in vi mode, you can esc-/ to search, esc-k to call the last command, and once editing a command, cw to change word, $ to go to the end of the line, etc...

I do not buy "I'm a vim person, but I just use ctrl-R and the arrows", because you are basically limiting yourself just because you had not realised readline is a full editor. You have nothing to learn, just set the editor mode in your preferred editor mode, and start using it, trust me, you will start getting use to it and use its power very quickly.

BONUS: It' snot just bash! Any program that use readline can do the same! psql etc... use it (or a something like readline, because of GPL vs non-gpl etc...).

BONUS 2: You can use readline with software that don't use it, it's call rlwrap. Go ahead, use "rlwrap sqlplus" once, then try to use oracle without it!

Your remark is valid. But admit that this post created the discussion. And led to interesting information sharing.

So I +1 your comment. And I +1 the article too.

> ctrl-R is not bash, it's GNU readline

As readline was codeveloped with bash, I think it's incorrect to say it's not bash. It is bash by way of readline - additional information important for some contexts, not for others.

> cw to change word, $ to go to the end of the line, etc...

But not, sadly, ci" to change what's inside quotes.


As to your obviously troubling experiences with some vim users, I apologize on behalf of my sect. But tone down your characterizations - there are plenty of smug and superior emacs users as well. (For my part, I don't much care what others use as long as they actually learn their way around some sort of powerful editor.)

I'm a vim person myself. my issue isn't with vim vs emacs, but that people who choose vim as their editor don't switch their command line editing to vim mode, and find it both worse and ironic when it comes to the subset of vim users who are vocal against emacs!

I think there's a fair amount of room for a workflow that does most meaningful commandline manipulation inside the editor, in which case leaving vim in emacs mode and "just" knowing C-r and C-x C-e could be sort of reasonable.

I certainly understand being skeptical of "vim modes" - they are often incomplete in painful ways. As mentioned above, I often run up against the limitations of bash vim mode when trying to change what's inside quotes.

I'm the kind of person you're ranting about here, but...thank you.

+1 just for rlwrap.

Another very useful feature related to brace expansion are sequences:

{1..99} will give 1 2 3 4 5 .. 9 10 11 12 .. 98 99

{01..99} will give 01 02 03 04 05 .. 09 10 11 12 .. 98 99

And so on. I think it also works with letters.

Brace expansion can also be nested:

  $ echo {a..c}{1..5}
  a1 a2 a3 a4 a5 b1 b2 b3 b4 b5 c1 c2 c3 c4 c5
It is worthwhile noting that brace expansion is strictly textual and is performed before any other expansion.

> I think it also works with letters.

Indeed it does. According to the man page : "When characters are supplied, the expression expands to each character lexicographically between x and y, inclusive, using the default C locale."

$ echo {a..z}

a b c d e f g h i j k l m n o p q r s t u v w x y z

But it does not seem to work with ranges outside ASCII such as "à..é", "あ..お", or smileys range, even though my locale should be ".UTF-8" compliant.

Also, you can specify an increment value :

$ echo {0..42..7}

0 7 14 21 28 35 42

$ echo {z..a..3}

z w t q n k h e b


And as your last example illustrates, downward ranges are automatically invoked:

  $ echo {10..1}
  10 9 8 7 6 5 4 3 2 1
As are negative endpoints (shown below with some automatic number formatting, which is turned on when either the first or the second endpoint is padded):

  $ echo {2..-002}
  0002 0001 0000 -001 -002
I just noticed that all this is documented behavior -- another illustration of how rococo this shell has become.

> Indeed it does. According to the man page : "When characters are supplied, the expression expands to each character lexicographically between x and y, inclusive, using the default C locale."

I think 'x' and 'y' are probably the worst variable names they could have chosen for this sentence :)

My best progress in shell was by switching to Fish. Much more intuitive for programmer. Guess what this does:

  while true
    sleep 1

I second this. No shortcut to search history, just start typing and hit up. Instead of ctrl-e or whatever it is, it has the same "move by 1 word" shortcut as literally everything else on the computer. The pre-made prompt configurations that you can browse (with preview!) in a web browser is nice too. ZSH doesn't compare imo.

Interestingly, none of the two Bash versions in the comments are equivalent to your code, which kind of prove your point with Bash being tricky. `while sleep 1` means the script will sleep once before running `df`, while it should only sleep after. The other command also won't work because it's missing colons between commands.

The point I wanted to make was that OP sacrificed compatibility with all major distros for being rid of "; do", essentially.

I just don't see the point. Bash might have flaws, nothing is perfect, but it's one vital piece of software that most distros have installed.

  while sleep 1; do

watch -n1 df

I second the voices, one downvoted but none really addressed, wondering why this is manifestly an improvement over the bash equivalent.

I certainly don't demand that everything in Fish be an improvement over everything in bash for Fish to nonetheless be superior... but this was presented specifically as an example of how Fish is great, and I could just as well say "Guess what this does" of the obvious bash equivalent:

    while true; do
        sleep 1


Eep, yes.

Do you use Ctrl+R a lot? You should give fzf a try: https://github.com/junegunn/fzf

It works for both Vim & Bash.

Another good read:

Bash Shortcuts For Maximum Productivity [0]

[0] http://www.skorks.com/2009/09/bash-shortcuts-for-maximum-pro...

One more handy one, when you have a complex command to deal with: C-x C-e will open up the current command line in your text editor, and when you save and quit, it'll run the line. So if you want to do some complex editing operation on the command line, you can do so with your preferred editor.

I know of "M-." which will insert the last word of the previous command, and typing "M-." again will replace it with the last word of the command before that.

Is there something that goes through the words, instead? So I hit a key, it inserts the last word of the previous command, then I hit the key again and it replaces it with the penultimate word of the previous command?

I think using bang, I can do "!-3:1" to get the second word of the command three lines up?

> Some people hold the belief that using a GUI is faster than using a CLI.

I've heard more people say this than that GUI is faster. Also it really depends on what you are doing.

I think Coding Horror gave a fairly succinct overview, including sources[1]. As usual, it's incomplete understanding and cargo-culting of opinions until the statement in question bears little resemblance to the original assertion.

1: https://blog.codinghorror.com/revisiting-keyboard-vs-the-mou...

I rather use a REPL environment that combines GUI and CLI, like in Xerox and ETHZ OSes.

Think of DrRaket, Swift Playgrounds or Jupyter like experience.

Yes, there's far too little of this. I'd love something that combines the good points of Powershell and a GUI file explorer for example. Even the primitive out-gridview or ogv is incredibly handy.

Powershell is probably the closest we have currently in terms of that experience.


    alias ssh=’ssh -AX’
    alias ls=’ls –color=auto’
Let me quote the Mercurial manual:

> It is possible to create aliases with the same names as existing commands, which will then override the original definitions. This is almost always a bad idea![0]

I was recently bitten by this when running a build on a new machine. I was doing a

    log -r "$revision"
and instead of getting one commit message (as usual), I was getting the entire log history up to $revision.

I managed to find that Mercurial had made a breaking change[1] so that `log -fr` would now have the observed behavior. But I was only running `log -r`!

But on the old machine, I had in my .hgrc the alias

    log=log -f 
To top it off, I also had a comment with the above quote that this is "almost always a bad idea!" Consider me burned!

[0] https://www.selenic.com/mercurial/hgrc.5.html#alias

[1] https://www.mercurial-scm.org/wiki/UpgradeNotes#A3.4:_minor_...

Also (more specifically to one of the given examples), enabling `-A` on all your ssh invocations likewise seems like a pretty bad idea.

Given the title of the article, I was really hoping that the author would answer the following question. Suppose I have the following line:

>rsync ~/20160604/apache-tomcat-7.0.63/webapps/ROOT/contact.html apache-tomcat-1:/svr/apache-tomcat-7.0.63/webapps/ROOT/

I'm rsyncing the contact.html file to my website. Now I want to rsync the index.html page. I do this by:

1. Pressing the up arrow key to get the previous command.

2. Press and hold the back arrow key until it gets to "contact.html"

3. Press and hold backspace to delete "contact.html" and type "index.html"

My question is: How to quickly move the cursor to a location on the line. For example, in Vi I could do "F+c" twice to move to the first "c" if this were a text file. I know I can enabled Vi commands for Bash, but this seems cumbersome. There has to be a way in Bash to jump around the already typed line.

Yet another option:

Typing "Ctrl-r aString" will recall the previous command and position the cursor where the string "aString" occurs. You can then Alt-d, Ctrl-w, whatever.

cf http://stackoverflow.com/a/2215511

Oh hey, this is definitely the closest / fastest to what I want. Although if I cut and paste a line from another window, I still need a way to jump to some position in that line.

Last resort is Ctrl-x Ctrl-e :)

Maybe you are asking a different question than this, but this should work:

> $ mroe file1 ; mroe file2

> $ !!:gs/mroe/more

But instead, you would do:

>$ rsync ~/20160604/apache-tomcat-7.0.63/webapp /ROOT/contact.html apache-tomcat-1:/svr/apache-tomcat-7.0.63/webapps/ROOT/

> $ !!:gs/contact/index

I've added word hopping ctrl-left / right keybindings to my ~/.inputrc (you can also put it in your .bashrc but .inputrc works for all readline programs including bash):

The readline manual shows more sophisticated argument operations. Zsh, IIRC, has more features for command processing.

My habit is: Ctrl-x Ctrl-e after your step 1. (Note: be sure to have your $EDITOR set)

Otherwise, typing ^contact^index after your step 1 should also work.

It's not as precise as vi movement, but for most command line activities I find the Emacs-like movements sufficiently practical:

M-b: back one word

M-f: forward one word

C-a: beginning of line

C-e: end of line

I also don't like to use the arrow keys because they are so far away, so:

C-b: back one character

C-f: forward one character

C-p: previous command

C-n: next command

And since I'm making a list now anyway:

C-k: Kill to end of line.

C-u: Kill to beginning of line.

C-y: Yank (put/paste) last killed string. You can then cycle further through the kill ring with M-y.

But I have a question concerning Emacs movement: M-b and M-f are rather similar to vim's b and e, respectively, meaning they don't jump to the beginning/end of the non-whitespace-string. That's why vim has B and E. Is there anything similar in Emacs?

If you do man-bash, and look for the READLINE header, you can see all of the navigation and history manipulation functions available to you. Of particular interest would be forward-word, backward-word, and edit-and-execute-command.

The equivalent in Emacs mode (the bash default) is Ctrl+].

Alt+<number> followed by that goes to that <number> occurrence of the character, so "Alt+4 Ctrl+] c" would go to the 4th c. Ctrl+Alt+] searches backwards in the same way.

But I find just about anything better.

!!:s/contact/index/ ^contact^index alias r='fc -e - --' # if not already present r contact=index

or if you know ahead of time, do them both together

rsync ~/20160604/apache-tomcat-7.0.63/webapps/ROOT/{contact,index}.html


Since you know how to do this in vi, do a Ctrl+x Ctrl+e to open the command in $EDITOR. Closing the editor will execute whatever was edited in it.

There's also a shell builtin `fc` (mnemonic: fix command) that does this.

He talks about using ^ substitution in the article. You could do: ^contact^index

I use fish. It's not a popular choice of a shell, but the autosuggestions feature saves a LOT of time.

I use fish also. Its more popular than people admit because it makes things easier.

Did you know Ctrl + / is like undo while composing a command? So when you for example delete a word with Ctrl + W, you can get it back with Ctrl + /.

History manipulation in bash only reminds me why I have both the current commands history number and the last return code in my prompt.

I don't need colors, or anything fancy in my prompt, but those two things I find to be really useful.

  export PS1='[\u@\h \W](\!/$?)$ '

So happy to see this article get traction, it truly deserved it! Many unknown Bash tricks!

I featured it in the cron.weekly newsletter 2 weeks ago: https://www.cronweekly.com/issue-44/

I like this article a lot. A lot of funny tricks to try and learn.

A missing piece of information IMHO: Ubuntu now maps a nice readline features to PgUp and PgDn: history-search-backward and history-search-forward.

Type the beginning of a command line, and with PgUp-PgDn, you will traverse your history for the command lines beginning with what you have typed.

That's a no-brainer in my Bash life.

Note: to enable that feature in your Bash, here is a tutorial: http://dqxtech.net/blog/2011-03-06/linux-bash-history-pgup-p...

Related: BASH FAQ - http://mywiki.wooledge.org/BashFAQ

Also, look at the screen tips by the same author - http://samrowe.com/wordpress/2010/06/16/gnu-screen-quick-tip...

I almost never use any of the "shortcuts" explained. And I wonder if it would be worth learning them. They look much more cumbersome than the alternatives, I use in my everyday work.

I have to admit, that -- at some time in the past -- I've even tried to activate vim mode. As a heavy vim user i thought it would make sense.

At the end I'm stuck with the Emacs-inspired (is it really Emacs?) shortcuts.

They seem to be the ones that make most sense in the short living, very interactive, shell command line:

- Arrows for going up/down one or two commands,

- ctrl-r for interactive searching in the history,

- ctrl-a for going back to the beginning of the row,

- ctrl-e to the end,

- del & and backscape for deleting a bunch of chars,

- in some case ctrl-w for deleting words backwards (mostly for deleting the url in the latest wget command),

- and, of course, tab completion.

When I'm in need for more complex interactions:

- I start vim and

- work with a mix of !! commands (shell that outputs the result in the current vim buffer),

- vim manipulations (vertical selections, ctrl-x-f, qq short living macros), A and I with a . repeat),

- join everything in a row and yank it and, finally,

- a :!ctrl-r" to run it.

When the interaction is even more complex, than it's time for a shell script.

Last resort being a Python script.

Now, why would I take the time to write `rm my-file{-01,-02,old}` and risk getting a typo into it, instead of relying on the tab-autocomplete?

C-x C-e to edit the command line with EDITOR=vim in your .bashrc (or whereever you keep your configurations). When it quits it'll run the command for you. You don't need to join the lines. It's like a temporary shell script.

  $ C-x C-e
  # in vim
  ipushd dir
  do stuff
Everything gets run.

> Now, why would I take the time to write `rm my-file{-01,-02,old}` and risk getting a typo into it, instead of relying on the tab-autocomplete?

If you write `rm my-file{-01,-02,old}` and then press tab, it will expand it for you before you run it.

I've tried this and I don't get any expansion on tab. Is this a Bash or Zsh feature?

Hmm, could be zsh.

You definitely should read the comments about "history-search-backward" and "history-search-forward". There are a real nice addition to your list.

yes, that looks like a useful command...

does not work here on a mac, but i can think of using it!

thanks for mentioning.

the usual configuration of a .inputrc is given for a PC keyboard.

the safest method for you is to edit your ~/.inputrc with vi(m). go to insert mode,

type "

type Ctrl-v

type PgUp (->a strange string is displayed),

type the following string ": history-search-backward

Do the same on another line for PgDn (replace backward with forward).

Save. Relaunch a Bash session. And that's it.

I didn't realize that you could do something like: vim <(find . | grep coolfile) until just the other week, pretty dang useful.

I often use `git grep something | vim -` which puts list of files into vim with line numbers, and then I do `gF` to get to file and particular line.

I didn't realize vim supported reading from standard in, thanks!

You can go one further. I have an alias 'cbuf=vim - -ccbuf!'

This takes whatever is piped in and loads it into the quickfix list. So I get locations out of anything with lines of the format "file:line: something" or "file:line:col: something".

Eg: git grep -n | cbuf

One of my favorite discoveries as well! I sometimes (rarely) compare archives with:

    diff <(tar tzf f1.tgz) <(tar tzf f2.tgz)
Or diffs of diffs:

    diff <(git diff --cached) the-patch-alice-proposed

[Danger, do not try to run in your system] I like this :(){ :|: & };: which is a fork bomb http://askubuntu.com/questions/159491/why-did-the-command-ma...

How do you, as a root, protect against it? It's unseemly that a non-root can DoS a system.

Should set user process limitations, in /etc/security/limits.conf

Tip for "set -o vi" users: when you have issued a long multiline command and your line wrapping isn't working very well, Esc-k until you get to the command and then press v - this will open your command in vi and you can now edit it more easily. Quitting with :wq will execute your command.

Strictly it will open your command in $EDITOR, but if you've "set -o vi" that's probably vi/vim/neovim.

Outside vi mode, C-x C-e does the same thing.

It's "edit-and-execute-command" in readline. Incidentally, this really does what it says on the tin: if you use "read -e" to enable readline support at a prompt, and you try to edit what you're inputting this way, it won't pass the result into the read - it will try to execute it.

I used to do !$ a lot until I configured iTerm to allow me to cycle through the last args with alt-. which is way faster. But I did not know about the colon modifiers, so !$ might make its way back into my workflow. ZSH gives me a nice overview of what's possible:

    > !$:<tab>
    &  -- repeat substitution
    A  -- absolute path resolving symbolic links
    Q  -- strip quotes
    a  -- absolute path
    c  -- PATH search for command
    e  -- leave only extension
    g  -- globally apply s or &
    h  -- head - strip trailing path element
    l  -- lower case all words
    q  -- quote to escape further substitutions
    r  -- root - strip suffix
    s  -- substitute string
    t  -- tail - strip directories
    u  -- upper case all words

A trick I used to use in the floppy disk era:

    $ mount /mnt/floppy
    $ mv !$/file_I_needed .
    $ u!mo
The last command would umount(8) the floppy.

I use !! all the time, specially when first using find to see which files I will operate on and then doing the actual operation:

    $ find . -name '*Foo*.scala'
    $ git add "$(!!)"
Shameless plug: I actually use nq, my find wrapper: https://github.com/rbonvall/nq

My favorite tip in this vein is "fc" => Fix Command, along with "#my_command --here".

If you're unsure of a command, press insert a leading "#" to make it a comment (Up-Arrow, Ctrl-A, #, Enter). Then "fc" will load that command into $EDITOR where you can have full text edit capabilities before writing and exiting the file to execute the command.

I know there's some magic keystrokes to get into vi-mode from the command line but I can never remember them, whereas "fc" is pretty easy to remember for the rare occasion when I need it.

The magic keystrokes are whatever fires the "edit-and-execute-command" command.

If you're in emacs mode, it's C-x C-e. Mnemonic: e for editor, x because it's emacs and lots of stuff starts with C-x

If you're in vi mode, it's v from normal mode, so if you're in insert mode it's escape, then v. Mnemonic: v for vi

One that I love that is missing:

    M-# (i.e. alt-shift-3)
Comments the line currently being edited and places it at the top of history. Great when searching back through history and editing a line safely before executing it.

One note I wish the author would add is that ^a to move to the beginning of a line often conflicts with screen or tmux as a command prefix, so I tend to use ^x^x as a replacement.

I wouldn't ever day that the GUI is the fastest way to interact with a computer. It's just the safest and simplest.

Those are usually more important then speed.

I thought that i knew more than i actually know. Thanks!

Bash has lots of cool features, but zsh has more and better defaults, and fish is even better.

This is tight. Thanks for sharing, the history portion at the beginning is really cool.

"Some people hold the belief that using a GUI is faster than using a CLI."


^a I would remember it

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact