6 ms·
'!!:n' selects the nth argument of the last command, and '!$' the last arg A lot of people know about "!$" (which is shorthand for !!:$), but that's just the t
by unfletch 14y ago
'!!:n' selects the nth argument of the last command, and '!$' the last arg
A lot of people know about "!$" (which is shorthand for !!:$), but that's just the tip of Bash's history expansion. I use these things all the time. One of my favorite keystroke savers is adding :h, the head modifier, to !$. For example:
$ cp file.txt /some/annoyingly/deep/target/directory/other.txt
$ cd !$:h
$ pwd # => /some/annoyingly/deep/target/directory
Once you understand how each component works it's easier to put them together into new (to you) combinations. For example, once you know that !$ is shorthand for !!:$, it's not a huge leap to reason out that you can use !-2:$ to get the last argument to the 2nd-to-last command. Or !ls:$ for the last arg to the most recent `ls` command.
I also prefer to do substitution with the :s modifier rather than ^ as suggested at the link, for consistency's sake:
$ echo "foo bar"
foo bar
$ echo !!:s/bar/baz
foo baz
$ echo !?bar?:s/foo/qux
qux bar
Relevant Bash manual pages:
http://www.gnu.org/software/bash/manual/html_node/Event-Designators.html http://www.gnu.org/software/bash/manual/html_node/Event-Desi...
http://www.gnu.org/software/bash/manual/html_node/Word-Designators.html http://www.gnu.org/software/bash/manual/html_node/Word-Desig...
http://www.gnu.org/software/bash/manual/html_node/Modifiers.html http://www.gnu.org/software/bash/manual/html_node/Modifiers....
- jschmitz28 14y agoThat first example is great, thanks. I run into that all the time. Up until now I've been doing this: $ cp file.txt /some/annoyingly/deep/target/directory/other.txt $ cd !$ (No such file or directory) (up arrow and then backspace to directory)
- cschol 14y agoAlt + . – use the last word of the previous command. $ cp file.txt /some/annoyingly/deep/target/directory/other.txt $ cd then press Alt + . $ pwd # => /some/annoyingly/deep/target/directory
- ralph 14y agoNo, that gives the last word, as you say, we want the dirname of the last word. $ echo foo/bar foo/bar $ echo !$ !$:h foo/bar foo
- cschol 14y agoGood point. I usually don't supply the file name of the second argument. Then it would be equivalent.
- kragen 14y agoSo you say cd M-. M-backspace M-backspace instead of cd M-.. Four keystrokes is still an improvement over shift-1 shift-4 shift-; h, which is five, plus you get to see where you're going to go before you get there.
- ralph 14y agoYou're incorrect. The number of M-backspace you appear to need would seem to depend on how many `little' words comprise the part that needs deleting, e.g. foo/2013-03-13 needed three M-backspace to rid me of the date and a further backspace to remove the trailing slash, which isn't insignificant to all commands, e.g. ls -ld bar/ when bar is a symlink. In comparison. !$:h understands its task at a higher level. And thanks to key rollover, typing different characters, like !$:h, is quicker than tapping away at . until visual feedback, which may lag, tells me I've done enough.
- kragen 14y agoIt's true that M-backspace is occasionally less convenient, but it's usually more convenient.
- pjungwir 14y agoAnother nice ending is `:p` to print the command instead of executing it. I use this if I'm doing something complicated and I want to make sure it's right. Or if I'm saying `!-n:foo` with n>2. Then just up-arrow and enter to run it for real.
- kejadlen 14y agoI use magic-space for that in my inputrc: $if Bash Space: magic-space $endif Basically does the same thing as :p, but after a space instead of enter. Edit: fixed formatting.
- cawel 14y agoHere is a detail when using '!!:n' with ':p' when trying to iteratively construct a complex command. I want to emphasize the use of the up-arrow (which will show the interpolated arguments), as opposed to rewriting exactly what you wrote in the previous command, since the usage of ':p' will be interpreted by the shell as a command in itself: $ echo a b c d a b c d $ echo !!:2:p echo b $ echo !!:2 -bash: :2: bad word specifier # there was only 1 argument in last command However: $ echo a b c d a b c d $ echo !!:2:p echo b $ <up-arrow pressed once will give the following prompt> $ echo b
- absqua 14y agoshopt -s histverify to show the expanded command before executing it. Then just enter. I never get these right the first time.
- pyre 14y agoIn zsh, you can hit <tab> to expand it in place before hitting <enter>.
- sciurus 14y agoA sometimes handy addition to the s modifier is g, which replaces all instances of the pattern instead of just the first. $ echo "foo foo" foo foo $ echo !!:s/foo/bar echo echo "bar foo" echo bar foo $ echo "foo foo" foo foo $ echo !!:gs/foo/bar echo echo "bar bar" echo bar bar
- hiroaki 14y ago$ !! runs the previous command. This is especially useful: $ !! $ sudo !!