How to quickly change the first word in a Bash command?

44

28

I would like to improve my workflow a bit with Bash, and I realize I often want to execute the same command to a different executable.

Some examples:

Git (where I would like to quickly change the second word):

git diff     foo/bar.c
git checkout foo/bar.c

Cat/rm (where only the first word has to be changed):

cat foo/is/a/very/long/path/to/bar.c
rm  foo/is/a/very/long/path/to/bar.c

I know I can hit Ctrl+a then Del to remove the first word, but I am wondering if there is a quicker way to do it.

nowox

Posted 2015-01-22T07:36:28.733

Reputation: 1 779

Duplicate of Run two commands on one argument (without scripting).

– Scott – 2015-01-22T21:28:58.280

Honestly, I think it's safest to just use Ctrl+a and delete. It's definitely not very slow. – agweber – 2015-01-22T21:45:24.487

Answers

56

!$ expands to the last word of your previous command.

So you could do:

cat foo/is/a/very/long/path/to/bar.c

rm !$

or:

git diff foo/bar.c

git checkout !$

Your examples happened to only repeat the last word, so !$ worked fine. If you actually had a lot of arguments that you wanted to repeat, and you just wanted to change the first word, you could use !*, which expands to all words of the previous command except the zeroth.

See the "HISTORY EXPANSION" section of the bash man page. There's a lot of flexibility there.

Spiff

Posted 2015-01-22T07:36:28.733

Reputation: 84 656

16

Right and proper. I would like only to put a warning: with !$ you have no full visual control of the line you are running. This can result harmful sometimes. Specially if you incur in a missprint. It takes from the history what to expand. So if you write the last command with a blank space in the beginning, probably this command will not finish in the history. When you will execute your new command with !$ the shell will not take the parameters from the last command line typed but only from the last of the history. Here same more words.

– Hastur – 2015-01-22T15:03:01.197

1@Hastur You could set your shell to expand history on tab or upon enter to prevent accidents. – slhck – 2015-01-22T22:05:53.250

2@Hastur that's why you need to press intro twice in zsh (shameless promotion) – Braiam – 2015-01-23T23:43:43.350

@Hastur - When I have any doubt about what's going to happen or I belatedly realize I have to do something else first before running something long I have just typed in, I go to the beginning of the line and add a # or an echo so I can see it and it goes into history so I can get it right back and run it again without the disabling prefix. – Joe – 2015-01-26T21:13:03.690

28

Ctrl+a to go to the beginning of the line, then Alt+d to delete the first word.

jjlin

Posted 2015-01-22T07:36:28.733

Reputation: 12 964

9

The delete word shortcut is actually Meta+d, and Meta is usually mapped to Alt on Linux machines. On platforms where this is not the case, an alternative to get the Meta modifier is to use the Escape as a prefix. See http://en.wikipedia.org/wiki/Meta_key

– Gustavo Giráldez – 2015-01-22T15:04:31.057

2@GustavoGiráldez if you wanna go deep, then Meta+D is only valid if emacs is enabled (via set -o emacs or simply by default). It won't work in inferior editor-mode or if emacs is disabled. – TC1 – 2015-01-23T01:13:18.497

In many terminals (because this is a terminal thing and not a Bash thing), the home key will also go to the beginning of a line. Many laptops map Fn + Left to the home key. Similarly, the end key will usually go to the end of the line. I've yet to use a terminal emulator that doesn't support these hotkeys. – Kat – 2015-01-23T23:52:43.523

1@Mike On the other hand, C-a and M-d are much faster to type if your hands are already in typing position. – jjlin – 2015-01-24T01:11:46.440

@Mike This is a bash thing. Type cat and compare what you get when pressing Home (^[[H here) and when pressing Ctrl+a (^A). – Jonas Schäfer – 2015-01-24T13:36:08.950

@TC1 Flagged as offensive for disparaging the far superior editor that is Vim. (just kidding of course ;) ) – Doorknob – 2015-01-25T16:03:45.017

17

I'm not sure if it would actually be faster or not, but see this article, particularly point #.3:

  1. Replace a string from the previous command using ^str1^str2^

In the following example, first we executed the ls command to verify a file. Later we realized that we want to view the content of the file. Instead of typing the whole file name again, we can just replace the “ls” in the previous command with “cat” as shown below.

$ ls /etc/cron.daily/logrotate

$ ^ls^cat^
cat /etc/cron.daily/logrotate

Benguin

Posted 2015-01-22T07:36:28.733

Reputation: 201

15

Alt+.

If you need only to repeat the last part of one of the previous commands you can use Alt+. that will paste the last argument taken from the last line of the history.

If pressed more than one time will substitute what just pasted with the last argument of the line before...

E.g. if the last 2 commands were:

cat foo/is/a/very/long/path/to/bar.c
pico foo/is/a/very/long/path/to/SomeWhereElse.c

In the shell I write rmand I press Alt+. it will appear:

rm foo/is/a/very/long/path/to/SomeWhereElse.c

if I press again Alt+. it will appear instead

rm foo/is/a/very/long/path/to/bar.c

and so on...

Hastur

Posted 2015-01-22T07:36:28.733

Reputation: 15 043

Not sure why but this does not work on my Mac console. – lulalala – 2015-03-27T06:45:33.677

Here there are the keyboard shortcuts that are known to work with bash. BTW Are you sure you're using bash as shell?

– Hastur – 2015-03-27T08:14:46.170

1I guess this is a Mac thing. When I type that I get – lulalala – 2015-03-27T08:18:59.543

1

It seems that "To use the Alt Key Shortcuts in OS X - Open Terminal Preferences | Settings Tab | Keyboard | Tick "Use option as meta key". This link is specific for Mac... let me know...

– Hastur – 2015-03-27T08:24:14.007

12

In addition to @jjlin answer, you might be interested by the following tips:

  • Ctrl+w deletes the word to your left
  • Ctrl+k deletes from cursor to the end of command line
  • Ctrl+u deletes from cursor to the start of command line
  • Alt+b moves cursor one word backward
  • Alt+f moves cursor one word forward
  • $_ contains last argument of the previous command line

For more about these, lookup "Readline Command Names" section of the bash manpage.

eg:

cat foo/is/a/very/long/path/to/bar.c
rm $_

maiki

Posted 2015-01-22T07:36:28.733

Reputation: 421

Those are nice tips, but they don't answer the question. – slhck – 2015-01-22T09:09:45.613

@slhck IMHO it does because the question title doesn't match the given examples. If we focus on the examples, as I did, the title should be "How to quickly change a word in a bash command?". This is also why my answer is "in addition to @jjlin" 's one. But I guess the question should be clarified. – maiki – 2015-01-22T09:21:21.057

The OP always wants to remove (exchange) the first n words in the command, with n = 1 in the first example and n = 2 in the second. jjlin's answer shows how to delete the first word (and by re-applying the shortcut, delete up to n words). Your answer lists a few Bash shortcuts (which are indeed useful), but none of them are efficient ways to delete the first n words. – slhck – 2015-01-22T09:27:16.527

Hm, reading again, the $_ parameter would probably work if there is only one argument (i.e. if n = m - 1 where m is the total number of arguments). The remainder of shortcuts is irrelevant to the question though. – slhck – 2015-01-22T09:29:58.483

@slhck For the sake of arguing I've read the first example as "replace the 2nd word" :-) – maiki – 2015-01-22T09:32:46.397

8

If you are proficient in vi, you can activate vi bindings in bash (most shells?) by using the command set -o vi. Then, you can use the normal vi keys to edit your command. In your first example, you could do ^wcw to delete "diff", then change it to checkout.

It may not be worth learning the vi keybindings just to edit the command line, but if you know them already it's a neat productivity booster.

Chaosed0

Posted 2015-01-22T07:36:28.733

Reputation: 181

I learned on kornshell, so set -o vi was how I lived! I even do this in my bash prompts too. – bgStack15 – 2015-01-22T14:48:33.937

bindkey -v for zsh. Esc 0 c w – user530873 – 2015-01-22T16:29:33.933

6

There are many ways to skin this cat!

To replace a specific string, ^old^new^extra will take your previous command, replace old with new, and append extra. You may stop as early as you like; e.g. ^old will replace old with the empty string and append the empty string (essentially deleting old and doing nothing more).

1. ^diff^checkout
2. ^cat^rm

Especially useful variant of this:

for i in `seq 1 10`; do echo something complicated; done
# inspect the output to see if it looks right
^echo

To replace a specific word, you can use !m:n-p to refer to words n through p of the command m (use negative numbers to count back from the current command). You can omit the -p part to refer to a single word, and omit the :m-p part to refer to an entire command. Special forms !! for !-1, !$ for the last word of the previous command, and !* for the arguments (all but word 0) of the previous command are pretty handy.

1. !!:0 checkout !!:2-
2. rm !*

I often use both of these; zsh is especially nice here, as hitting tab will expand the cryptic stuff out to make sure you got it right.

There are also so many ways to do this with line editing. Read up on your shell's keybindings.

Daniel Wagner

Posted 2015-01-22T07:36:28.733

Reputation: 903

-2

Most terminal programs support...

  • Press <Up-Arrow> as needed to redisplay one of the previous command lines from history.
    • Press <Down-Arrow> as necessary to move forward through history list.
  • Press <Left-Arrow> as needed to move cursor to end of second word.
  • Press <Backspace> as needed to erase second word.
  • Type in replacement second word.
    • Press <Right-Arrow> / <Left-Arrow> as necessary to reposition for more changes.
  • Hit <RETURN> to execute the command

If the command line you want was not recent, do a reverse-i-search with <Ctrl-r> as described in question ...
Is there a way of using ctrl-r after typing part of command in bash?
Then edit via the arrow keys as needed.

DocSalvager

Posted 2015-01-22T07:36:28.733

Reputation: 310

-3

What I do (Ubuntu/bash):

1) Arrow up hey to return previous command
2) Home key to return to beginning
3) Modify command as needed.

Idiot-proof and especially useful for multi-line commands.

Vorac

Posted 2015-01-22T07:36:28.733

Reputation: 457