Score:16

How do I rerun the second-to-last command?

cn flag

I'm using Ubuntu 21.10. If I mess up, I can re-run the last command with !!. Here's an example:

$ apt update
Reading package lists... Done
E: Could not open lock file /var/lib/apt/lists/lock - open (13: Permission denied)
E: Unable to lock directory /var/lib/apt/lists/
W: Problem unlinking the file /var/cache/apt/pkgcache.bin - RemoveCaches (13: Permission denied)
W: Problem unlinking the file /var/cache/apt/srcpkgcache.bin - RemoveCaches (13: Permission denied)
$ sudo !!
sudo apt update
[sudo] password for [me]:
...
Fetched 336 kB in 2s (206 kB/s)
Reading package lists... Done
Building dependency tree
Reading state information... Done
98 packages can be upgraded. Run 'apt list --upgradable' to see them.

That's fine, but instead of rerunning the previous command, how can I run the one before it? Like this:

$ echo hi
hi
$ echo hello
hello
$ !!   <-- I'm trying to get that to run 'echo hi'
hello

Basically, here's what I'm looking for

$ echo hi
hi
$ echo hello
hello
$ ???   <-- What can I put here to get it to run 'echo hi'?
echo hello!
hello!

So, given that !! runs the last command, how can I run the command before the previous one? In my example, instead of typing !!, what can I run to execute echo hi?

raj avatar
cn flag
raj
The shortcuts like `!!` were useful in plain old `sh`, where there was no command history and editing. In `bash`, there's no more need to use them as you can freely go to previous/next commands by pressing up/down arrow.
bac0n avatar
cn flag
`echo $(!-2)`, there's also a possibility to embed event designators.
cg flag
If you want to run the command before you ran the previous one, I'd suggest using a time machine add-on to bash. Whereas, if you want to re-run the command before last, that's a different story.
cg flag
Yes... "re-run the command before last" or "re-run Nth command from history"
Itération 122442 avatar
us flag
+1 because you taught me about !! :)
br flag
JoL
@raj In agreement with bac0n, I also use them for embedding. Sometimes I run one command, then another, then I want to compare the outputs, and do something like `diff -u <(!-2) <(!!)` or `comm -23 <(!-2 | sort) <(!! | sort)`. Another common use of history expansion for me is `!$` to reuse the last argument of the previous command in a new one, like `aur fetch foo` to make a build directory for an AUR package foo, then `cd !$` to change the working directory to it.
Peter - Reinstate Monica avatar
hn flag
https://man7.org/linux/man-pages/man3/readline.3.html, Ctrl-F "Commands for Manipulating the History"
Score:41
au flag

You can use the up-arrow and down-arrow keys to cycle through your command history. So to re-run the second-last command, you'd press up-arrow twice, then return.

This has several advantages over methods like !-2. Most importantly (in my opinion), you can see the command and make sure it's the one you intended to re-run before pressing return to execute it. Even aside from simple mistakes ("oops, I guess it was the third command back that I wanted"), bash history may not count previous commands the way you expect because of options like ignorespace, ignoredups, and the HISTCONTROL variable.

Also, interactive command recall lets you easily edit the command before re-running it. You can do that with history recall modifiers as well, but again doing it interactively lets you see your edits before executing the recalled/modified command.

Plus if you're lazy like me, up-arrow up-arrow return is easier to type than (shift)exclamation minus 2 return

Quasímodo avatar
jp flag
"Most importantly (in my opinion), you can see the command and make sure it's the one you intended to re-run before pressing return to execute it." If you enable `histverify` then any command with history substitution will need to be confirmed before parsed by the shell. However, I am lazy like you so I would favor your suggestion in this particular case.
Ruslan avatar
bv flag
If you prefer to retain your hands around the home row, rather than wandering over the keyboard, an easier combo would be Ctrl-P (memorize as "Previous") instead of the UpArrow, and Ctrl-N (as for "Next") instead of the DownArrow. Thus, Ctrl-PP, Return.
Nate T avatar
it flag
With a major downside being a lack of scriptability. At least in any sensible form.
Akbarkhon Variskhanov avatar
mx flag
You can also press M-^ (i.e. Alt+Shift+6 or ESC Shift+6) to initiate history expansion on the current line.
Score:35
hr flag

From the HISTORY EXPANSION section of man bash:

!-n    Refer to the current command minus n

So to run the command before last, you can use !-2

In fact, !! is just a synonym of !-1

tw flag
You mean computer scientists start counting from zero when going forward, but from -1 when going backwards? Where did these nerds learn to count?
SusanW avatar
in flag
@MikeMaxwell must just be a quirk of history :-D
OmarL avatar
sy flag
@MikeMaxwell, in this case, 0 is what you're currently entering; -1 is the previous command, -2 is the previous but one. It makes sense to me :-)
HiddenWindshield avatar
us flag
@OmarL So, if the next command I'm going to type is going to be `echo "The stock market is going to be X"` in two hours, does that mean I can use `!1` to see what the stock market is going to be two hours from now?
OmarL avatar
sy flag
@HiddenWindshield That's ... creative, but no dice: `-bash: !1: event not found`
Score:7
tz flag

!-n execute command "-n" of your history, but I wouldn't recommend it, as it is "instant" and will not give you time to check first that the "Nth" command is the right one you need to execute again... ( @bac0n nicely remarked that you can set : shopt -s histverify to switch it to "non instant": it will let you verify the command !-n expands to, before executing it with <Enter>)

However, if you are using bash as your shell, I much prefer to recommend using the search feature:

Ctrl and then type something, which is the part of the command that you are looking for. (ex: Ctrl + r + (type into terminal) echo)

It will present the latest occurrence in your history matching something (i.e., matching the search term that you typed after Ctrl + r).

Subsequent Ctrl + r will look further back in your history. Or adding letters will precise the search.

And once you find a good match, press Enter to execute it again (or Ctrl + c to exit from the search without executing the currently displayed matching command).

Additional tip: if, instead of Enter , you press Ctrl + o , it will execute the selected history command AND present the next one, ready to be executed with Enter (which only execute that one and returns to the normal prompt) or Ctrl + o again (which executes it and present the next command in your history). Very useful to repeat a sequence of steps, and providing a display of those commands before executing them.

And each time you use those things, you are allowed to change something on the currently displayed line (using the left or right arrow key to move within it), such as a parameter, a server name, etc., and execute that modified line + go to the next one (if you pressed Ctrl + o).

bac0n avatar
cn flag
It's depended on how you set up the shell option... you can append `shopt -s histverify` if you don't want to run the entry directly.
Nate T avatar
it flag
Also, you might add that this is bash specific. Most modern shells have history tracking / rerun in one form or another, but the implementation and syntax / shortcuts will be different from one shell to the next.
tz flag
thanks @NateT and bac0n , 2 good points I omitted in my answer. I edited it in.
Ruslan avatar
bv flag
To complement Ctrl-R for `reverse-i-search`, there's Ctrl-S for forward `i-search` (useful when you missed the right entry and need to go "back"), though there's [a caveat](https://stackoverflow.com/q/791765/673852).
tz flag
@Ruslan adds an interresting thing, but I didn't bother to add that one as it is less often used and it is sometimes linked to other things (ctrl-s [stops the terminal from outputting characters] ctrl-q [resumes the character output], for exemple, by default in lots of shells. See https://unix.stackexchange.com/a/72092/27616 ). Some additionnal setting (of readline? and stty) may be required to set it all working, and exemples can be found on unix.se
Ruslan avatar
bv flag
@OlivierDulac that's exactly the caveat that my link addresses :)
tz flag
@Ruslan : oops, didn't notice that one, sorry ^^
Score:4
cn flag

If you run

history

you'll get a list of the last 'n' commands entered. The history size defaults to 500 commands. So, as explained by steeldriver, the command before last one can be rerun with

!-2

and yes, the third to last will be

!-3

and so on. For more details, use

man history

and search for Event Designators.

kopaka avatar
cn flag
A small addition: you can run a specific command from the history by just using `!312` (to run the command with the line number 312 shown in your history output). Even more useful tip: If you had a typo in that command, you can run `!312:p` which will not execute the command but still put it on top as "last used command". This helps you in editing longer commands without manual copy-paste from the history by simply using arrow up and editing the command before running it.
Latkar avatar
cn flag
Great! The list of modifiers of "history" is full of surprises. Thanks!
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.