bang-dollar — History expansion `!$` — last argument of the previous command across all 5 shells
Equivalents in every shell
!$Expands to the LAST argument of the previous command, parse-time. `!^` is the FIRST argument; `!*` is ALL arguments; `!:N` picks argument N (zero-indexed: `!:0` is the command itself). `Esc-.` (also `Alt-.`) is the inline keyboard equivalent — inserts the value into the current line for editing.
!$Identical POSIX-style word designators (`!$`, `!^`, `!*`, `!:N`) plus zsh-specific modifiers — `!$:h` (head, drop file from path), `!$:t` (tail, drop dir), `!$:r` (root, drop extension), `!$:e` (extension only). Composable: `!$:h:t` is the parent directory name.
$history[1][-1]No `!$` shortcut. `$history[1]` is the last command (a string); split it with `string split " " -- $history[1]` if you want fields. Most fish users press `Alt-.` (history-token-search-backward) to insert the previous command's last word inline, edit, then run.
((Get-History -Count 1).CommandLine -split ' ')[-1]No first-class `!$`. PSReadLine binds `Alt-.` to `YankLastArg` — same UX as bash's `Esc-.` keystroke. `Set-PSReadLineKeyHandler -Chord Alt+. -Function YankLastArg` to confirm or rebind.
(no equivalent)cmd.exe has no last-argument operator. Workaround: copy from console with mouse selection (Quick Edit Mode) and paste with right-click. The `for /f` loop can split the previous command if you captured it, but there is no live history-arg recall.
Worked examples
Touch a file, then edit it (the canonical bang-dollar example)
touch report.md && vim !$touch report.md && vim !$touch report.md; and vim $history[1][-1]New-Item report.md; vim ((Get-History -Count 1).CommandLine -split ' ')[-1]Strip the filename to get just the parent directory of the last argument
cd "$(dirname !$)"cd !$:hUse ALL arguments from the previous command
cp !* /backup/cp !* /backup/Gotchas
- Inside DOUBLE-quotes bash still expands `!$` — `echo "use !$"` will substitute, not print literal `!$`. Single-quote (`echo 'use !$'`) or escape (`echo "use \!$"`) for the literal form. Same gotcha as `!!`; same fix.
- Bang expansion is PARSE-TIME, not lazy. By the time you press Enter, `!$` is already the previous command's last word — there is no live preview unless you use `:p` (`!$:p` echoes without running). On a destructive command, `!$:p` first then re-up-arrow is the safety dance.
- In zsh, modifier composition is left-to-right but order matters: `!$:t:r` (basename, then strip extension) ≠ `!$:r:t` (strip extension first, then take basename) — for `/var/log/app.log.gz`, the first gives `app.log`, the second gives `app.log.gz`. Read the chain right-to-left in your head if the result surprises you.
- Fish's `$history[1][-1]` index-of-index syntax does naive whitespace splitting; it breaks on quoted arguments containing spaces (`vim "report draft.md"` becomes `draft.md"`). For string-aware splitting use `string split` with care, or rely on `Alt-.` interactive insertion.
- PSReadLine's `Alt-.` repeatedly walks BACKWARDS through previous commands' last arguments (press multiple times). Bash's `Esc-.` does the same. This is the keyboard ergonomics most people actually use day-to-day — `!$` is for scripts, not for typing.