202

For example:

[root@ip-10-0-7-125 ~]# history | grep free
  594  free -m
  634  free -m | xargs | awk '{print "free/total memory" $17 " / " $ 8}'
  635  free -m
  636  free -m | xargs | awk '{print "free/total memory" $9 " / " $ 10}'
  736  df -h | xargs |  awk '{print "free/total disk: " $11 " / " $9}'
  740  df -h | xargs |  awk '{print "free/total disk: " $11 " / " $8}'
  741  free -m | xargs | awk '{print "free/total memory: " $17 " / " $8 " MB"}'

I'm just wondering if there any way to execute the 636 command without typing it again, just type something plus the number, like history 636 or something.

Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
The One
  • 4,862

5 Answers5

345

In bash, just !636 will be ok.

user164825
  • 3,636
  • 16
    In Linux - This has more to do with the shell (bash, zsh, etc) a person is running then the OS you are running it on. There are shells on linux without support for history. – Zoredache Apr 08 '16 at 18:06
  • @Zoredache And similarly, this works fine in most implementations of bash on Windows. – Ajedi32 Apr 08 '16 at 18:14
  • 1
    Not just bash, of course, but other shells too - including csh. – Drew Apr 09 '16 at 15:19
  • 14
    If you've got a command that's very similar to what you want to run, you can append :p to print the command without running it, !636:p for example. Which means that you can easily select it again from your history by pressing the up arrow and make the minor changes you want – AJefferiss Apr 14 '16 at 07:27
  • Very powerful stuff – J011195 Nov 08 '23 at 11:55
100

Yes, it's called "history expansion." See

LESS='+/^HISTORY EXPANSION' man bash

for full details.

Using an exclamation point followed by a number is arguably the simplest use:

!636

However, you can also run the last executed command directly without knowing its history number:

!!

Or you can run two commands back:

!-2

The form I most often use, however, is to repeat the last argument of the last command:

echo this text goes into a file > /tmp/afile.txt
cat !$

Or, let's say I'm inspecting a file. Using tab completion, I might do the following:

ls -l /really/long/path/to/some/file
less !$

Again, read the man page for more details:

LESS='+/^HISTORY EXPANSION' man bash
Wildcard
  • 36,499
  • 29
    Interactively, Alt-. can be more convenient than !$. It inserts the last argument of the last command verbatim into the line. – ulidtko Apr 08 '16 at 12:08
  • 2
    @ulidtko Where are those special escapes documented (I knew about !$, but never heard about Alt-.)? Will you post a link to it, please? – edmz Apr 08 '16 at 13:26
  • 5
    LESS="+/DEFAULT KEY BINDINGS" man 3 readline, /etc/inputrc, ~/.inputrc. Many programs besides bash use libreadline; for those who do, you get the same features like Alt-., Ctrl-X-U (undo), Ctrl-/ (describe shortcut), tab-completion, etc -- for free. For example, with just three lines of PYTHONSTARTUP one can enable tab-completion and history in the stock python REPL. Which will work (mostly) the same as in bash, since it's the GNU Readline library that does the work. The readline's manpage describes the features in detail. – ulidtko Apr 08 '16 at 14:44
  • 2
    Also, Ctl-UpArrow (or AltUpArrow on bash) will scroll backwards through the history list. Typing a few characters then the UpArrow gets only the commands starting with that letter, e.g. "fr(Ctl-Up)" scrolls through all the "free..." commands in the OP's list. This also works in things like gnuplot & gdb that use readline. – jamesqf Apr 08 '16 at 17:06
  • @jamesqf: It sounds like you're describing history-search-backward, but the bash man page doesn't list a default binding for it. Did you have to configure that in .inputrc? It does sound useful, though. I knew about M-. (yank-last-arg) and C-r / C-s, and stuff like M-C-e (shell-expand-line)... Either that or my terminal emulators are broken: In konsole and xterm (Ubuntu 15.10), I just get A characters from the end of the ^[[1;3A escape sequence that alt+up generates. Same for ctrl+up. – Peter Cordes Apr 08 '16 at 18:13
  • "the last argument of the last command" Hmm, but in the example you gave, /tmp/afile.txt wasn't the last argument, or even an argument at all. It was the target of output redirection. Does it just get the last token maybe? – Ajedi32 Apr 08 '16 at 18:22
  • 2
    @Ajedi32, see the final bolded line in my answer. :) Truthfully this answer is barely a taste of what history expansion can do. Keep in mind that this is at the level of the shell, not the command you are calling; hence echo {1..5} followed by touch !$ will touch five files, not just one. So strictly speaking it's not the last argument but the last shell word on that line. (Also try echo hello >temp followed by echo goodbye !$.) If you can think of a way to put it more clearly feel free to suggest an edit. – Wildcard Apr 08 '16 at 18:36
  • @Peter Cordes: You're right, I've had those bindings in place for so long (decades?) that I'd forgotten they weren't a default part of the system. On my system (I use tcsh and xterm) '"\e[415z": history-search-backward' is the line in .inputrc and .tcshrc. '421z' binds forward search to down arrow, others allow editing of the recovered line. There's also the whole subject of completion rules, which I frankly don't really understand, but which should allow edited lines to be automagically expanded using only allowable values... – jamesqf Apr 08 '16 at 20:24
19

A nice one, if you don't want to first history, note the number, etc:

in bash (and maybe others):

ctrl-r something 

(ctrl-r = "reverse search interactively") (something = a part of a previous command)

This will show you the latest history line containing something . To get the one before, do ctrl-r (alone) again, each time it gets a previous line.

ex:

ctrl-r  10

to show the latest history line containing '10' (for exemple the line with $10, in your exemple), and ctrl-r again until you retrieve the history line you were looking for

When the line you wanted appear, just Enter to run it (or you can also edit it, using the arrow keys, backspace, and ctrl-a to go to the beginning of the line, ctrl-e to get to the End, ctrl-k : to "kill" from cursor to end of line (=deletes+saves it in a buffer), ctrl-y : to restore, from the buffer, a previously killed bit, etc.)

If you want to search forward (ctrl-s), you first need to disable XON : see https://stackoverflow.com/a/791800/1841533 :

" just to disable XON/XOFF by running

stty -ixon

" (and then you will be able to use ctrl-s, without having it freeze the terminal)

  • If I do this and accidentally press ctrl-r one time too many, is there some way to search forward in the history again? – kasperd Apr 09 '16 at 20:33
  • @kasperd: Yes you can. many answers on se points it out : ctrl-s for forward search. – Olivier Dulac Apr 09 '16 at 20:36
  • Unfortunately ctrl-s is used to freeze the terminal, and bash doesn't disable that, so that doesn't work in the default configuration. (Other programs - such as emacs - disables the keybinding to freeze the terminal such that ctrl-s can be used for searching.) – kasperd Apr 09 '16 at 20:43
  • @kasperd : Yes, sorry for not mentionning that earlier (I pointed "many answers" because they do precise that, but I didn't took the time to type this in the comment or give a link... (I was using my phone). I now came back home and could edit that in the answer above. ctrl-s for bash history search needs you to stty -ixon first – Olivier Dulac Apr 10 '16 at 00:17
  • That command is going to break normal use of ctrl-s, so that's not really an option. – kasperd Apr 10 '16 at 01:45
  • @kasperd: then just ctrl-c and start over (using a more specidic string if possible). For me, the stty is an option : I never needed to hang the terminal (was more useful în the typewriter days, I guess) – Olivier Dulac Apr 10 '16 at 07:51
  • When I have accidentally pressed ctrl-r too many times, I do press ctrl-c and start over. In case of a long running command where I need to briefly freeze terminal output to inspect it or copy something from the output, ctrl-c is not an option. There is no guarantee that the command can be started over with the same result, and even if it could, I may have to wait hours for it to reach the same point. – kasperd Apr 10 '16 at 08:17
  • you are mixing things: Ctrl-c in my last comment is for you to interrupt the ctrl-r and start the search again (with more precise string). About a long running cmd that you need to suspend a bit: you could freeze it with ctrl-z (=suspend), copy what you need, and fg(continue in foreground). Or use Putty or another and have it reset display on keypress only (not on new output, the default). or use | tee somefile, or script thecommand. And there are more ways (screen/tmux, etc). ctrl-s is not the only way to do it. – Olivier Dulac Apr 10 '16 at 08:33
10

You can use the shell builtin fc:

fc -s 636
Zombo
  • 1
  • 5
  • 44
  • 63
  • 3
    This is actually better than the accepted answer, but you have to remove the -s to get the benefits. If you run fc 636 you will open an editor with command 636 from your history in the buffer, and when you save and exit the command (modified or not) will be run. And even better, this one is POSIX-compliant. – Wildcard Oct 24 '17 at 01:56
  • @StevenPenny Thanks. And yes, I do know what POSIX is, though I don't see the relevance. Regardless, some easily accessed and included documentation would be nice. – Faheem Mitha Nov 11 '17 at 17:17
  • @FaheemMitha try running "help fc." – Wildcard Nov 11 '17 at 18:40
  • @Wildcard help is not POSIX - might have to do man dash or similar – Zombo Nov 11 '17 at 18:59
  • @Wildcard Thanks. I tend to forget help exists. Another shell builtin. And puzzling for unwary users who might want help with a new system, but instead are confronted with a stream of gibberish. :-( – Faheem Mitha Nov 11 '17 at 19:55
7

There is HSTR - hstr command for bash and zsh interactive command selection, better than Ctrl-R reverse search:

hstr interactive history command example

It's interactive, so you can search for, and edit the command, before executing it.

On Ubuntu, you can install hstr with the following one-liner:

sudo add-apt-repository ppa:ultradvorka/ppa && sudo apt-get update && sudo apt-get install hstr && hstr --show-configuration >> ~/.bashrc && . ~/.bashrc

or step by step:

sudo add-apt-repository ppa:ultradvorka/ppa
sudo apt-get update
sudo apt-get install hstr

Install hstr on Fedora, RHEL or CentOS:

sudo dnf install hstr -y

On macOS with homebrew:

brew install hstr

...then configure it with:

hstr --show-configuration >> ~/.bashrc

This will replace the default Ctrl-R behavior.

Run hstr --show-configuration to determine what will be appended to your Bash profile.

More configuration options available on project homepage at Github: https://github.com/dvorka/hstr

modlin
  • 255
  • 3
  • 7
  • 1
    HSTR is great! Note: The package to install is hstr not hh The config to profile command sets an 'hh' alias. – Matthew Mar 26 '21 at 22:15