# Bash history substitutions

# Quick Reference

# Interaction with the history

# List all previous commands
history

# Clear the history, useful if you entered a password by accident
history -c

# Event designators

# Expands to line n of bash history
!n

# Expands to last command
!!

# Expands to last command starting with "text"
!text

# Expands to last command containing "text"
!?text

# Expands to command n lines ago
!-n

# Expands to last command with first occurrence of "foo" replaced by "bar"
^foo^bar^

# Expands to the current command
!#

# Word designators

These are separated by : from the event designator they refer to. The colon can be omitted if the word designator doesn't start with a number: !^ is the same as !:^.

# Expands to the first argument of the most recent command
!^

# Expands to the last argument of the most recent command (short for !!:$)
!$

# Expands to the third argument of the most recent command
!:3

# Expands to arguments x through y (inclusive) of the last command
# x and y can be numbers or the anchor characters ^ $
!:x-y

# Expands to all words of the last command except the 0th
# Equivalent to :^-$
!*

# Modifiers

These modify the preceding event or word designator.

# Replacement in the expansion using sed syntax
# Allows flags before the s and alternate separators
:s/foo/bar/ #substitutes bar for first occurrence of foo
:gs|foo|bar| #substitutes bar for all foo

# Remove leading path from last argument ("tail")
:t

# Remove trailing path from last argument ("head")
:h

# Remove file extension from last argument
:r

If the Bash variable HISTCONTROL contains either ignorespace or ignoreboth (or, alternatively, HISTIGNORE contains the pattern [ ]*), you can prevent your commands from being stored in Bash history by prepending them with a space:

# This command won't be saved in the history
 foo

# This command will be saved
bar

# Repeat previous command with sudo

$ apt-get install r-base
E: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied)
E: Unable to lock the administration directory (/var/lib/dpkg/), are you root?
$ sudo !!
sudo apt-get install r-base
[sudo] password for <user>: 

# Search in the command history by pattern

Press controlr and type a pattern.

For example, if you recently executed man 5 crontab, you can find it quickly by starting to type "crontab". The prompt will change like this:

(reverse-i-search)`cr': man 5 crontab

The ``cr'` there is the string I typed so far. This is an incremental search, so as you continue typing, the search result gets updated to match the most recent command that contained the pattern.

Press the left or right arrow keys to edit the matched command before running it, or the enter key to run the command.

By default the search finds the most recently executed command matching the pattern. To go further back in the history press controlr again. You may press it repeatedly until you find the desired command.

# Switch to newly created directory with !#:N

$ mkdir backup_download_directory && cd !#:1
mkdir backup_download_directory && cd backup_download_directory

This will substitute the Nth argument of the current command. In the example !#:1 is replaced with the first argument, i.e. backup_download_directory.

# Using !$

You can use the !$ to reduce repetition when using the command line:

$ echo ping
ping
$ echo !$
ping

You can also build upon the repetition

$ echo !$ pong
ping pong
$ echo !$, a great game
pong, a great game

Notice that in the last example we did not get ping pong, a great game because the last argument passed to the previous command was pong, we can avoid issue like this by adding quotes. Continuing with the example, our last argument was game:

$ echo "it is !$ time"
it is game time
$ echo "hooray, !$!"
hooray, it is game time!

# Repeat the previous command with a substitution

$ mplayer Lecture_video_part1.mkv
$ ^1^2^
mplayer Lecture_video_part2.mkv

This command will replace 1 with 2 in the previously executed command. It will only replace the first occurrence of the string and is equivalent to !!:s/1/2/.

If you want to replace all occurrences, you have to use !!:gs/1/2/ or !!:as/1/2/.