80

Just a question to improve my bash skills. I always do this:

$ history | grep some_long_command

...
...
123 some_long_command1.........
124 some_long_command2.........
...

I can then run the command the command I found by doing:

!123

However, I often want to do this:

some_long_command1foobar

I.e. change the command before I run it. Can you use bash to run this command instead:

#some_long_command1

so it gets commented.

Then I don't have to use my mouse to highlight the command, edit it and then run it (I can just use the keyboard - faster).

I suppose I could write a script to do it but there might already be functionality built in somewhere....?

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
ale
  • 11,636
  • 27
  • 92
  • 149
  • 6
    The easiest way: put `bind Space:magic-space` in your bash profile. Then, pressing `Space` will expand `!123` into `some_long_command1`. – Blaz Sep 11 '13 at 17:40
  • @courteous: Thanks! That one was new to me. Very useful. – marlar Aug 27 '15 at 10:02

10 Answers10

145

I'd suggest instead of using the history command, you use ctrl+r and start typing that command. When you press an arrow key as if to go to modify it, it will drop out of autocomplete recognition, and will let you edit before running.

UPDATE: also, if you want to cycle through the different commands that contain the string you just typed, keep on pressing ctrl+r

Miquel
  • 15,405
  • 8
  • 54
  • 87
  • 8
    If you use vi keybindings (`set -o vi`), you can also use `/` to search the history and edit it. – William Pursell Jun 12 '12 at 16:09
  • 1
    A more powerful feature is allowing the typing in of a partial command or part of a path that was in a command then using the arrows to navigate the history. Search for history-search-backward, history-search-forward options for bash – DavidC May 23 '13 at 15:42
  • 2
    DavidC, I have seen others do this, but it doesn't work for me. When I type in the first few letters of a command, then I press up arrow, it ignores what I was typing and goes through history as though I hadn't typed anything at all (newest to oldest). How do you configure your shell to accomplish this? – Daniel Watrous Nov 27 '13 at 18:27
  • 1
    It's sad that the **up/down** doesn't scroll through the matches but exits immediately out of the search. I would have preferred it to scroll through the matches with **up/down** (indicating that I'm still looking for the command I want), and have only **left/right** exit out of the search (indicating that I have found the command I want and now I'm ready to edit it). – ADTC Mar 10 '14 at 08:03
  • 3
    @ADTC I just found out a way to do what you (and I) want: press `ctr+r`, start typing, then when you want to find all commands that contain that, simply keep pressing `ctrl+r`. In other words, what you want to do with up/down is done (in round robin fashion) with `ctrl+r` – Miquel Mar 10 '14 at 10:13
  • @Miquel Unbelievable that searching the bash was so simple. You saved me a lot of time and commands!! – Ajoy May 14 '14 at 15:39
  • Do not forget the `Ctrl+s` if you just missed a command with `Ctrl+r` – toolchainX Jun 08 '14 at 11:59
  • super cool command. Thank you. – Cuado Jun 10 '22 at 13:57
63

Actually, you can just append :p to the command to print it without actually running it. For example:

$ ls -la
$ !!:p

Will print out ls -la as the previous command without running it, and you can just press (up) to find it and edit it.

You can also do

!123:p

to print out the 123rd command as your previous command.

dayuloli
  • 16,205
  • 16
  • 71
  • 126
joeschmidt45
  • 1,932
  • 2
  • 17
  • 20
  • 2
    +1 The best answer, as it allows the usual history commands to answer the OP: `!mycmd:p`. If you have vi commands turned on in Bash, then Pursell's answer is just as good or better. Ctrl-r, as mentioned by Miquel is next best. – Brent Faust Dec 03 '13 at 19:18
  • If the 123 in not at begining of the line you can do: !?123?:p – Udi Jan 20 '16 at 11:19
20

You can also try fc command to edit the command in the history.

WIKI says,

​fc​ is a standard program on Unix that lists or edits and reexecutes, commands previously entered to an interactive shell. fc is a built-in command in the bash shell; help fc will show usage information.


Apart from reverse-incremental search(Ctrl+R), we have some more bash shortcuts:

From man bash:

previous-history (C-p)
    Fetch the previous command from the history list, moving back in the list. 
next-history (C-n)
    Fetch the next command from the history list, moving forward in the list. 
beginning-of-history (M-&lt)
    Move to the first line in the history. 
end-of-history (M->)
    Move to the end of the input history, i.e., the line currently being entered. 
reverse-search-history (C-r)
    Search backward starting at the current line and moving 'up' through the history as necessary. This is an incremental search. 
forward-search-history (C-s)
    Search forward starting at the current line and moving 'down' through the history as necessary. This is an incremental search. 
non-incremental-reverse-search-history (M-p)
    Search backward through the history starting at the current line using a non-incremental search for a string supplied by the user. 
non-incremental-forward-search-history (M-n)
    Search forward through the history using a non-incremental search for a string supplied by the user.
yank-nth-arg (M-C-y)
    Insert the first argument to the previous command (usually the second word on the previous line) at point. With an argument n, insert the nth word from the previous command (the words in the previous command begin with word 0). A negative argument inserts the nth word from the end of the previous command. Once the argument n is computed, the argument is extracted as if the "!n" history expansion had been specified.
yank-last-arg (M-., M-_)
    Insert the last argument to the previous command (the last word of the previous history entry). With an argument, behave exactly like yank-nth-arg. Successive calls to yank-last-arg move back through the history list, inserting the last argument of each line in turn. The history expansion facilities are used to extract the last argument, as if the "!$" history expansion had been specified. 
shell-expand-line (M-C-e)
    Expand the line as the shell does. This performs alias and history expansion as well as all of the shell word expansions. See HISTORY EXPANSION below for a description of history expansion. 
history-expand-line (M-^)
    Perform history expansion on the current line. See HISTORY EXPANSION below for a description of history expansion.
insert-last-argument (M-., M-_)
    A synonym for yank-last-arg. 
operate-and-get-next (C-o)
    Accept the current line for execution and fetch the next line relative to the current line from the history for editing. Any argument is ignored. 
edit-and-execute-command (C-xC-e)
    Invoke an editor on the current command line, and execute the result as shell commands.
Community
  • 1
  • 1
Prince John Wesley
  • 62,492
  • 12
  • 87
  • 94
11
!123:gs/old/new/

Will run command 123 replacing the string 'old' with the string 'new'.

John Lawrence
  • 2,923
  • 17
  • 23
6

You can get to edit mode by hitting M-^ (option-shift-6 on a mac).

Type this:

!123M-^

And you'll be editing command #123. It's sort of like using ctrl-r, but starting with exclamation-point syntax.

James Moore
  • 8,636
  • 5
  • 71
  • 90
4

Instead of using the history command, bind history-search-backward/history-search-forward to key shortcuts which can be remembered easily (I prefer PgUp/PgDown). To do that, put this into your .inputrc file:

"<key code>":  history-search-backward
"<key code>":  history-search-forward

To get <key code>, type Ctrl-V <key> in the shell, and replace the starting ^[ with \e in whatever was output.

After this is set up, you can just type some and press PgUp to get some_long_command. If you need some_long_command with_some_arg but there is a similar command some_long_command with_some_other_arg later in the history, you can cycle through until you reach it by typing some and then hitting PgUp repeatedly, or you can type some, hit PgUp, move the cursor to where the two commands start to differ, type a few characters and hit PgUp once more. This ability to quickly page through / differentiate between similar commands makes it in my opinion a much more comfortable tool than Ctrl-R.

Tgr
  • 27,442
  • 12
  • 81
  • 118
3

You can also put

shopt -s histverify

in your .bash_profile, which causes any history expansion to appear on your command line without running it, allowing you to edit before doing so.

chepner
  • 497,756
  • 71
  • 530
  • 681
1

You may wan to try "suggest box"-like history https://github.com/dvorka/hstr - it reads Bash history and allows for quick navigation.

hh

To get the last command simply type hh, navigate to the command and use right arrow to get it on command line (where you can edit it and/or add comment).

Martin Dvorak
  • 790
  • 8
  • 15
0

^p to get the last typed command in unix/solaris

0

Put

alias r='fc -s'

in your .bashrc (home dir) then you can just type in

r <whatever>

at the command prompt and you will execute a copy of the last <whatever> command (same params) that is in your history. just hit up arrow to see what you have executed if you feel the need.

Sebastian Lenartowicz
  • 4,695
  • 4
  • 28
  • 39
chuck
  • 1