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


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'.

  • 6
    This answer might help – Michael Mrozek Nov 3 '10 at 21:50
  • 9
    Not an answer to your question, but <ctrl>+R will allow you to interactively search your history and then immediately execute if you find what you were looking for. – kasterma Nov 3 '10 at 22:25

! 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.

  • 5
    I find Ctrl-P Ctrl-J to be pretty fast; faster than Up Enter, at least. – ephemient Nov 5 '10 at 1:55
  • 29
    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. :) – malvim 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 1 '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 6:07

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.

  • 4
    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. – erikbwork 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 9:19

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

  • Upvoted this. None of the other answers had any of these clever tricks. – Gergely Lukacsy Feb 15 '17 at 14:38
  • Upvoted because www.thegeekstuff.com is simply a fantastic resource, and this was one of the few linux articles I hadn't seen before. Very helpful. – Steve Benner Jan 30 '19 at 9:16
  • This is what I was looking for. – Sridhar Sarnobat Jan 24 '20 at 20:39

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 !$


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

  • 2
    Ah, I was hoping to find this. How does it behave with two args? – Jonathan Jun 6 '19 at 16:23
  • 1
    It'll just reuse the last argument of the two. $touch f1 f2 and then $vim !$ will evaluate to $vim f2 – Teshan Shanuka J Jun 7 '19 at 4:33
  • 1
    There's also a way to reuse argument ranges. I don't remember the exact syntax, but it would go something like this: !:2- – Sridhar Sarnobat Jan 24 '20 at 20:40
  • 1
    @SridharSarnobat Yeah apparently you can. Just a did a small research and it's super useful. I'll update the answer – Teshan Shanuka J Mar 20 '20 at 10:37

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.