In my article, Parsing Bash history, I demonstrated how to reference items in your shell history
by line number as well as by word position. Once you've mastered parsing Bash history
by line and word index, you can benefit from the modifiers available to the history
command.
The histexpand shell option
Before discussing history
parsing, it's worth mentioning that the exclamation point (!
) notation is only available to your Bash shell thanks to the histexpand
option. Because histexpand
is enabled by default, many users never give it much consideration. However, it's the option that enforces expansion of a !
to the list of history
entries.
Should the option be toggled off, you lose this functionality. For example:
$ echo foo
$ set +o histexpand
$ !-2
bash: !-2: command not found
$ set -o histexpand
$ !-3
echo foo
foo
Generally, histexpand
is on by default, except in non-interactive shells (for instance, in a shell script). Should history
shorthand ever fail you, you can either activate histexpand
as a shell option or else use the full history
command implied by histexpand
:
$ echo foo
$ set +o histexpand
$ history -p !-2
echo foo
foo
In a shell script, you must activate history
and provide a location where history
can be saved:
HISTFILE=/tmp/history.log
set -o histexpand
set -e
## some code here
## clean up
rm /tmp/history.log
An advantage of leaving histexpand
deactivated is that you lose the verbosity of the results of history
actions. For instance, with histexpand
activated, the first thing returned to your shell after a history
command is the expanded version of what's being run:
$ set -o histexpand
$ echo foo
foo
$ !!
echo foo
foo
With histexpand
toggled off, your history
command is longer, but the results are more terse:
$ set +o histexpand
$ echo foo
foo
$ !!
foo
Whether you find a use for history
in a shell script is up to you, but history
modifiers have some interesting shortcuts that make them particularly convenient in some cases.
History modifiers
Modifiers to history
selections are designated by a colon (:
) followed by one modifier character. Some modifiers may be combined with others.
Filename suffix
To drop the suffix of an argument, use the r
modifier.
This is similar to basename
.
$ ls -lgGh aLongFileNameWith-a_complex-syntax-1.tgz
-rw-r--r-- 1 0 Mar 9 11:23 aFileNameWith-a_complex-syntax-1.rev.tgz
$ echo !!:2:r
echo aLongFileNameWith-a_complex-syntax-1
aLongFileNameWith-a_complex-syntax-1
The r
modifier isn't super-intelligent. It just finds the final dot in a filename and chops off the suffix, which sometimes may not match what you think of as the file suffix, so in some ways, basename
offers greater flexibility.
$ set +o histexpand
$ ls -lgGh aLongFileNameWith-a_complex-syntax-1.tar.gz
$ echo !!:2:r
aLongFileNameWith-a_complex-syntax-1.tar
The opposite result can be attained with the e
modifier:
$ set +o histexpand
$ echo aLongFileNameWith-a_complex-syntax-1.tgz
aLongFileNameWith-a_complex-syntax-1.tgz
$ echo !!:2:e
.tgz
Filenames
A simple version of dirname
is available with the h
modifier:
$ set +o histexpand
$ echo src/spacer.sh
src/spacer.sh
$ echo !!^:h
src
And the other side of that expression is available with the t
modifier:
$ set +o histexpand
$ echo src/spacer.sh
src/spacer.sh
$ echo !!^:t
spacer.sh
String substitution
Possibly the most broadly useful modifier of history
is string substitution. For instance, any admin of a mixed environment has typed this into a Red Hat Enterprise Linux box at some point:
$ sudo apt install tmux
Such a mistake is easy to fix with string substitution:
$ ^apt^dnf
sudo dnf install tmux
You can even add on some options:
$ ^apt^dnf -y
sudo dnf -y install tmux
This history
syntax is shorthand for the s
modifier. The full syntax is, for example, !!:s/apt/dnf
and therefore can be useful for items several lines back in your history
. Assume you issued a useful command three commands back, and want to run a similar command now:
$ !-3:s/vi/emacs/
sudo dnf install -y emacs
Like sed
, this substitution by default only occurs once, but you can make it global (in relation to the line you're recalling) with the g
modifier:
$ pip update pip
[...]
$ !!:gs:/pip/pip3/
pip3 update pip3
Safety first: how to perform a history dry-run
Pressing Return
after a modified history
line can sometimes be stressful, especially when the line you want to re-run is nestled between particularly dangerous commands or affects important files. If you want to verify the command you're about to modify and run, you can use the p
modifier at the tail end of a history
modification.
$ !-32:0-:s/mv/trash/:p
trash important.txt status.txt pay.txt
The command you see as a result is the expanded item from history
, but it hasn't been run yet. You can run it manually, by pressing the Up
arrow or Ctrl+P
, now that it's been resolved for you. Using verification (p
) is generally a good idea if you're new to using the history
command in production.
Wrapping up
Your Bash history can be useful for many things, whether it's looking back at what you've been doing all day, or just making your work more efficient by reusing chunks of information you've already worked to figure out. The more you practice with history modifiers, the more useful they become. Allow yourself to (carefully) stumble through some as you learn the syntax, and soon you'll be recalling commands and arguments with fewer key-presses than ever before.
[ Want to try out Red Hat Enterprise Linux? Download it now for free. ]
About the author
Seth Kenlon is a Linux geek, open source enthusiast, free culture advocate, and tabletop gamer. Between gigs in the film industry and the tech industry (not necessarily exclusive of one another), he likes to design games and hack on code (also not necessarily exclusive of one another).
Browse by channel
Automation
The latest on IT automation for tech, teams, and environments
Artificial intelligence
Updates on the platforms that free customers to run AI workloads anywhere
Open hybrid cloud
Explore how we build a more flexible future with hybrid cloud
Security
The latest on how we reduce risks across environments and technologies
Edge computing
Updates on the platforms that simplify operations at the edge
Infrastructure
The latest on the world’s leading enterprise Linux platform
Applications
Inside our solutions to the toughest application challenges
Original shows
Entertaining stories from the makers and leaders in enterprise tech