A shell exclamation mark is not for yelling. Be lazy. | Filip Roséen - refp.se<br>A shell exclamation mark is not for yelling. Be lazy.<br>Event designators have been hiding in not-so-plain-sight since the late 1970s — so powerful that forgetting might be part of a massive conspiracy to wear out developer keyboards faster than otherwise.
Published5 August 2026 at 20:12 UTCAuthorFilip RoséenTags#shell<br>#bash<br>#zsh<br>#posix<br>#unix<br>Table of Contents<br>Don't yell at your colleagues; yell in your shellCommand-line repetition we socially accept
Don't Repeat Yourself.<br>An in-depth explanation of Event DesignatorsEvent Designator<br>Word Designator<br>Modifier
POSIX and the power of fc<br>Yell responsibly<br>Frequently Asked QuestionsWhy not use ctrl-r instead of memorizing a bunch of things?<br>Why not use alt-. instead of !$?<br>Are you not disregarding other useful features?<br>! just gets in the way, how do I turn this off?
Further Reading
Don't yell at your colleagues; yell in your shell #
You and I are probably very different; my choice of editor is likely to<br>make you cringe just thinking about it, and your favorite programming language<br>is statistically — definitely — not mine.
There is however one thing (and maybe that's the only thing) we all have in<br>common; we are a bunch of lazy bastards.
Note : This article is primarily targeting bash, csh, tcsh, and<br>zsh. If these shells are not your daily driver, see POSIX and the power of fc<br>— worth a read no matter which POSIX-compatible shell you use.
Command-line repetition we socially accept #
$ ssh some-user@10.240.33.109<br>$ echo "done with some-user@10.240.33.109" >> ~/work/superfun-client/worklog<br>$ cd ~/work/superfun-client && cat TODO<br>$ ssh some-user@10.240.33.109 #
I am sure we have all ended up in arrow-up-mashing hell when repeating commands<br>in our shell history, but what if we instead could save ourselves the trouble<br>and refer to previous commands and their arguments directly?
$ ssh some-user@10.240.33.109<br>$ echo "done with !:1" >> ~/work/superfun-client/worklog<br>$ cd !$:h && cat TODO<br>$ !ssh
No yelling — just exclamation marks.
Note : The magic described in this article applies to interactive shells<br>unless configured otherwise, it is not meant to be used in your new<br>amazing.sh shell script.
Don't Repeat Yourself. #
I bet you've heard it before, "do not repeat yourself", either from that<br>annoying colleague with all the obscure magic (who might smell a little funny) —<br>or perhaps you said it yourself during the last refactor session that somehow<br>lasted longer than the federation delay on matrix.org.
$ apt install awesome-package # insufficient permissions<br>$ sudo !! # repeat with sudo
Most of us have heard DRY repeated since we were ki–, I mean junior. But is it<br>not funny that we've religiously been taught to apply DRY everywhere… except on<br>the command‑line?
$ touch ~/projects/work/awesome.sh<br>$ cd !$:h # cd to the directory of awesome.sh
$ ssh 10.240.33.109 -p2222 -i ~/.ssh/prod/ed25519<br>$ ssh 10.240.33.110 !:2* # same flags, another host
$ ffmpeg -i /recordings/a-sunny-day.mov !#:2:r.mkv<br>ffmpeg -i /recordings/a-sunny-day.mov /recordings/a-sunny-day.mkv
$ scp !$:r.* example.com:/media<br>scp /recordings/a-sunny-day.* example.com:/media
An in-depth explanation of Event Designators #
Even though they might look mighty daunting at first glance, event<br>designators always follow the same rather simple pattern:
![event][:word][:modifier]<br>| | |<br>| | '--> modifier [ :h :t :r :e ... ]<br>| '-----------> which part [ :0 :$ :* :2-3 ... ]<br>'------------------> which line [ !! !-2 !ssh !?needle? ... ]
Note : In a hurry? Skip to posix and the power of fc for one of<br>the most useful albeit niche commands I have ever had the pleasure of<br>running.
Event Designator #
The first part immediately following the exclamation mark denotes which lines<br>we are interested in — a few examples:
$ !! # the previous line<br>$ !-2 # two lines back<br>$ !1337 # the 1337th line, as displayed by `history`<br>$ !ssh # the most recent line starting with "ssh"<br>$ !?dandelion? # the most recent line containing "dandelion"<br>$ !# # the current line, written so far
Note : If the ! is immediately followed by :, no explicit event is<br>specified and the expression will refer to the immediately previous line.
Word Designator #
After the event designator (if any) you may specify which part of the line<br>you are interested in. All examples below are written as if they follow the<br>command in the first code block.
$ /path/to/script.sh "hello world" --enable 1337
$ !:0 # 1st word => "/path/to/script.sh"<br>$ !:1 # 2nd word => "hello world"<br>$ !:$ # last word => "1337"
$ !:1-2 # 2nd to 3rd => "hello world" "--enable"<br>$ !:* # all args => "hello world" "--enable" "1337"
$ !:1- # all but last => "hello world" "--enable"<br>$ !:2* # 3rd to last => "--enable" "1337"
Note : There are several short-form expressions that work without even<br>specifying a colon, like !$ being equivalent to !:$, !* being equivalent<br>to !:*, and so forth.
Modifier #
Modifiers...