147

I used

history | less

to get the lines of previous commands and from the numbers on the left hand side I found the line I wanted repeated (eg. 22) and did

!22

at the command prompt and it worked -- executing the set of commands on the line I did at that time. I cannot figure out where the exclamation mark is used, what does it represent in terms of actions taken by bash, and where to use it. From the documentation I do not see an explanation that is 'tangible'.

Caleb
  • 69,278
  • 18
  • 196
  • 226
Vass
  • 5,271
  • 9
  • 38
  • 45
  • 7
    [This answer](http://unix.stackexchange.com/questions/6/what-are-your-favorite-command-line-features-or-tricks/67#67) might help – Michael Mrozek Nov 03 '10 at 21:50
  • 10
    Not an answer to your question, but +R will allow you to interactively search your history and then immediately execute if you find what you were looking for. – kasterma Nov 03 '10 at 22:25

5 Answers5

199

! invokes history expansion, a feature that originally appeared in the C shell, back in the days before you could count on terminals to have arrow keys. It's especially useful if you add the current command number to the prompt (PS1="\!$ ") so you can quickly look at your screen to get numbers for past commands.

Now that you can use arrow keys and things like Ctrl-R to search the command history, I don't see much use for the feature.

One variant of it you might still find useful is !!, which re-executes the previous command. On its own, I don't find !!Enter any faster than just Enter, but it can be helpful when combined into a larger command.

Example: A common pilot error on sudo based systems is to forget the sudo prefix on a command that requires extra privileges. A novice retypes the whole command. The diligent student edits the command from the shell's command history. The enlightened one types sudo !!.

Processing ! in this way is enabled in Bash by default in interactive shells and can be disabled with set +o histexpand or set +H. You can disable it in Zsh with set -K.

ilkkachu
  • 133,243
  • 15
  • 236
  • 397
Warren Young
  • 71,107
  • 16
  • 178
  • 168
  • 7
    I find Ctrl-P Ctrl-J to be pretty fast; faster than Up Enter, at least. – ephemient Nov 05 '10 at 01:55
  • 33
    If you just want to run the last command, Up/Enter is fine, but if you want to add to it in some way (say, you forgot to `sudo`, or something), then you can do `sudo !!`, for example. That might be a bit faster than "Up/Ctrl-A(or Home, if you are lucky enough)/sudo/space/enter". YMMV. :) –  Jan 14 '11 at 20:57
  • 1
    @AquariusPower: Just quote it. Either `echo 'Hi!'` or `echo "Hi!"` or `echo Hi\!`. All do the same thing. – Warren Young Jul 18 '13 at 16:14
  • 1
    `setopt NO_BANG_HIST` in zsh might be more memorable than `-K`. – gregory Jun 01 '19 at 20:09
  • 3
    kudos on the `enlightened ones` :) can't believe I've only been a diligent student this whole time... – Pedreiro Oct 23 '19 at 06:07
  • 2
    Important to mention that if you leave a space between the `!` and the command you will be negating its exit code(Boolean `not` operator). – Roland Apr 10 '20 at 12:01
  • Another trick: `Ctrl+p`, `Ctrl+a` then type `sudo `. Same number of key sequences typed as `sudo !!`, but I've got muscle memory from editing command lines this way, so it's faster for me. – TrinitronX Aug 10 '23 at 10:34
69

If there isn't a longer answer here there's certainly one on Super User, since I've read one recently. In the bash man page you can find a huge section titled HISTORY EXPANSION on the matter.

You can do a whole host more than just run the last command, or command number X. You can do things like !cat to run the last command that started with cat. Or !?bash?:s/bash/csh/ runs the last command containing bash but replaces it with csh.

Jeff Schaller
  • 66,199
  • 35
  • 114
  • 250
Cry Havok
  • 2,018
  • 14
  • 11
  • 5
    Although not directly an answer to OP's question, this needs way more upvotes. So useful! Thanks, Havok. – malvim Apr 30 '15 at 19:09
  • Uh, I should really look into the man page before I start googling. – erikbstack Jul 27 '15 at 13:39
  • 2
    `!!:s/bash/csh/` actually runs the *last command*, then replaces bash with csh, if present. Not the last command that included bash. That would be `!?bash?:s/bash/csh/` or maybe `!?bash?:s/%/csh/` – cde Jan 24 '16 at 14:31
  • Having used Bash extensively for several years, I was shocked to find that I had never known about this keyword before, and even though I have spent hours poring through the `man` pages, this feature is incredibly obscure. Thank you for pointing out the relevant section--that's the only place in the actual docs where they explain it sufficiently. – Steve Benner Jan 30 '19 at 09:19
54

A lot more can be done with ! such as:

  • execute a command which is typed before 3 commands: !-3
  • execute a command that starts with !ls

and a lot more. See 15 Linux Bash History Expansion Examples You Should Know

Mat
  • 51,578
  • 10
  • 158
  • 140
user379997
  • 751
  • 1
  • 6
  • 7
15

Of course you can do !! to reuse the last command in bash shell. And then there is !$ to reuse the last part of your last command.

e.g. view some file

less path/to/your/file.txt

If you now want to edit the same file, you can use !$ to get only the file path from the last command

vim !$

EDIT:

You can use all the arguments of the previous command with !*

e.g.: This will create some files and remove all of them

$ touch a.txt b.txt c.txt d.txt
$ rm !*

Again , you can use a specific argument of the previous command

e.g. This creates 4 files and will remove the 3rd file (c.txt)

$ touch a.txt b.txt c.txt d.txt
$ rm !:3

Similarly, you can use a range of arguments from the last command as follows

$ touch a.txt b.txt c.txt d.txt
$ rm !:2-4

This will reuse arguments 2 to 4 which evaluates the expression to rm b.txt c.txt d.txt

6

A friend of mine emailed me this:

It's part of GNU history library. In bash it is used to re-run commands in your history. If you want to be hardcore, grep for history_expansion_char in bash-4.1/lib/readline/histexpand.c for implementation details.

Michael Mrozek
  • 91,316
  • 38
  • 238
  • 232
Vass
  • 5,271
  • 9
  • 38
  • 45