You know that moment when you're staring at command line stuff and see something like !- or !$? First time I bumped into this exclamation mark on dash thing was during a server migration disaster. I'd copied what looked like a normal command from Stack Overflow, and bam – deleted the wrong directory. Took me three hours to recover. Felt like an idiot. But here's the thing: that little punctuation combo is way more powerful than it looks.
What Exactly Is Exclamation Mark on Dash?
At its core, exclamation mark on dash refers to using !- in Unix-like shells (Bash, Zsh, etc.). It's not one operator but two separate pieces working together: the history expansion (!) and the dash modifier (-). When you mash them together, magic happens.
Remember how Windows makes you click through folders? This is the terminal's power move. Say you run:
cd !-:1
That second line? It's grabbing the first argument (:1) from your previous command (!). So instead of typing the whole path again, you jump straight to /long/annoying/path/to/. Lifesaver when dealing with deep directories.
Where You'll Actually Use This
- Quick directory jumps after moving/copying files
- Reusing parts of long commands without retyping
- Chaining operations when debugging scripts
- Fixing typos in complex arguments (my personal savior)
Last week I saved 15 minutes on a deployment just by using !-2:3 to pull a path from two commands back. Felt like cheating.
Real-World Examples That Don't Suck
Forget textbook examples. Here's how exclamation mark on dash works in actual workflows:
Case 1: The Multi-Step Deployment
npm run build -- --env=production
# Step 2: Move output to server dir (using argument from Step 1)
mv dist/ !-:2
# Step 3: Restart service in that directory
systemctl restart myapp@!-:1.service
See how !-:2 grabs --env=production? And !-:1 takes dist/? That's three commands sharing arguments without retyping.
Case 2: The "Oh Crap" Correction
chmod 777 /important/system/config.yaml
# Fix permissions using previous argument:
chmod 600 !-:1
No frantic up-arrow + left-arrow mashing. Just reuse the path immediately.
Exclamation Mark on Dash vs. Other Shortcuts
People confuse this with regular history expansion. Here's the breakdown:
| Syntax | What It Does | When It Fails |
|---|---|---|
!- |
Arguments from previous command | If previous command has no arguments |
!! |
Repeat entire last command | Destructive commands (rm, shutdown) |
!$ |
Last argument of last command | Only gets one item |
!* |
All arguments of last command | Includes flags/switches |
Pro tip: Combine these like grep error !-:2/!$ to search in the last directory from two commands ago. Yeah, it looks like alphabet soup but saves hours.
echo first! Running rm -rf !-:1 without checking could nuke the wrong thing. Ask me how I know...
Weird Edge Cases I've Stumbled Into
Not all shells handle exclamation mark on dash the same. Here's where things get messy:
The Zsh Quirk
Zsh requires setopt hist_verify for safe expansion. Forgot this once during a live demo – expanded a git reset !-:1 and wiped uncommitted changes. Awkward silence.
When Commands Have Flags
Consider:
ls -l !-:1
Here, !-:1 expands to -o – not what you want! Solution: use !-:2 to skip flags.
Nested Commands Disaster
Never nest exclamation mark on dash like ssh server 'ls !-:1'. It expands on your local machine before sending. I learned this by exposing my ~/Documents path to a production server. Not ideal.
Handy Reference Cheat Sheet
Bookmark this table:
| Shortcut | Example Input | Expands To | Use Case |
|---|---|---|---|
!-:n |
ls !-:2 | ls /path/to/file | Get nth argument from last command |
!-^* |
chmod +x !-^* | chmod +x script.sh | All arguments except the first |
!-:x-y |
tar czf !-:2-4 | tar czf file1.txt dir/ config.json | Arguments range |
!-:0 |
sudo !-:0 | sudo apt | Command name only |
FAQs: Stuff People Actually Search
"Why did !- delete my file?"
Probably expanded to something unexpected. Always preview with echo !- first. History expansion doesn't care about your feelings.
"Is exclamation mark on dash safe for scripts?"
God no. It's interactive-only. Scripts should use $_ or variables. Learned this when cron jobs started failing mysteriously.
"Can I use exclamation mark on dash with sudo?"
Yes but it's tricky. sudo !! works, but sudo !-:2 expands before sudo. Better to do sudo $(history -p !-) in Bash.
"Why doesn't !- work in my terminal?"
Check:
- You're in Bash/Zsh (not Fish/sh)
- History is enabled (
set -o history) - No spaces in
!-(some setups require! -)
Pro Tips You Won't Find in Manuals
- Combine with search:
!?find?:2gets the 2nd argument from last 'find' command - Modify arguments:
vim !-:1:s/.txt/.md/changes extension - Skip dangerous commands: Add
#dangerafter commands you don't want to expand
A colleague showed me this trick for mass renaming:
convert "$f" !-:1:r.png
done
The !-:1:r grabs the root name of previous argument. Witchcraft.
When to Avoid This Like the Plague
Despite my love for exclamation mark on dash, never use it for:
- Any command involving deletion or formatting
- Scrips running as root (just don't)
- Automated CI/CD pipelines (use variables instead)
- When tired or distracted (trust me)
There's this infamous DevOps horror story where aws s3 rm s3://bucket/ !-:1 during migration expanded to aws s3 rm s3://bucket/ /. Bye-bye production bucket.
Bottom Line: Should You Bother Learning This?
If you live in terminal:
- Yes for interactive use – saves tons of typing
- No for scripting – too unpredictable
It's one of those things that feels awkward initially. I avoided it for years. But once you build the muscle memory? Honestly can't work without it now. Just treat it like a power tool – respect the danger, but damn it's efficient.
What's your exclamation mark on dash horror story? Mine involved a misused !- and a production database restore. We don't talk about that Monday.