# Bash and Zsh
## Keyboard Shortcuts (Bash & Zsh)
| macOS | Windows/Linux | Action |
|-------|---------------|--------|
| `Esc` then `.` or `Opt+.` | `Esc` then `.` or `Alt+.` | Insert last argument from previous command |
| `Ctrl+K` | `Ctrl+K` | Cut right (Kill) |
| `Ctrl+U` | `Ctrl+U` | Cut left (cUt); in Zsh kills whole line |
| `Ctrl+Y` | `Ctrl+Y` | Paste (Yank) |
| `Opt+W` | — | Clear line before cursor |
| `Ctrl+W` | `Ctrl+W` | Kill word |
| `Ctrl+X` then `E` | `Ctrl+X` then `E` | Edit current command in default editor |
`reset` — solve strange terminal situations
## History Expansion & Rerun Cheatsheet
|**Category**|**Syntax**|**Meaning / Example**|
|---|---|---|
|**Basic Re-run**|`!!`|Last command|
||`!n`|Command number _n_ from history|
||`!-n`|Command _n_ commands ago|
||`!string`|Last command starting with string|
||`!?string?`|Last command containing string|
|**Arguments from Last Command**|`!
|Last argument. `echo foo bar` → `!
= bar|
||`!^`|First argument. `cp foo bar` → `!^` = foo|
||`!*`|All arguments. `cp foo bar` → `!*` = foo bar|
||`!:n`|nth argument (0 = command itself)|
||`!:n-m`|Range of arguments|
||`!:n-
|From nth to last|
|**Substitution**|`!!:s/old/new/`|Replace first occurrence|
||`!!:gs/old/new/`|Replace all occurrences|
||`^old^new^`|Shorthand: rerun last command with first old → new|
|**Modifiers**|`:p`|Print the expanded command without executing|
||`:h`|Remove last path component (head)|
||`:t`|Keep only last path component (tail)|
||`:r`|Remove file extension (root)|
||`:e`|Keep only file extension|
||`:q`|Quote substituted words|
|**Other Tricks**|`!#`|Refers to current line typed so far|
||`fc`|Opens last command in $EDITOR for editing before rerun|
|**Combining**|`B && !!`|Run B then rerun last command A|
||`B && !string`|Run B then rerun last command starting with string|
||`history` + `!n`|Run command _n_ again (from history list)|
## Common `!!` Recipes
`!!` refers to the previous command and can be reused at will.
```bash
sudo !! # Rerun previous command as sudo
!! # Rerun previous command
!! > output.txt # Save previous command's output to file
```
See [[#Writing Output to File]] for more output redirection options.
## Managing History
**Delete a range of history entries (e.g. 100–110):**
```bash
for i in {100..110}; do history -d 100; done
```
Always delete from the starting line number repeatedly — each deletion shifts remaining entries up.
**Edit history file directly:**
```bash
# 1. Open history file
nano ~/.bash_history
# 2. Delete the lines you want
# 3. Save and exit
# 4. Reload history
history -r
```
## Job Control
[Job Control Documentation](http://web.mit.edu/gnu/doc/html/features_5.html)
- `Ctrl+Z` — pause current program and return to shell
- `fg` — resume job in foreground
- `bg` — run job in background
- `jobs` — list all jobs with their job numbers (`%1`, `%2`, ...)
**Queue a command after current one:**
1. `Ctrl+Z` to pause current command
2. Optionally `bg` to resume in background
3. `fg && command2` to resume in foreground and queue command2 after success
- Use `;` to run command2 regardless of success/failure
- Use `||` to run command2 only if command1 fails
**Detach process from terminal:**
1. `Ctrl+Z` to pause
2. `bg` to run in background
3. `disown -h [job-spec]` where `[job-spec]` is the job number (like `%1`) so it isn't killed when terminal closes
**Start detached from the beginning:**
```bash
./long_running_process options &
disown
```
**Sources:**
- <https://unix.stackexchange.com/questions/487955/how-to-plan-a-task-to-run-after-another-already-running-task-in-bash>
- <https://stackoverflow.com/a/625436/4700312>
## Directory Stack (`cd -`, `pushd`, `popd`)
`cd -` switches to the previous directory (stored in `$OLDPWD`). Same principle as [[Git - Miscellaneous#Switch to Previous Branch|git checkout -]] for branches.
```bash
cd - # previous directory
dirs -v # list the directory stack with indices
pushd /some/dir # push current dir onto stack, cd to target
popd # pop top of stack, cd back
```
| Feature | Bash | Zsh |
|---------|------|-----|
| `cd -` (previous dir) | Yes | Yes |
| `cd -2`, `cd -3` (nth previous) | No | Yes |
| `dirs -v` (list stack) | Yes (manual `pushd` only) | Yes |
| Auto directory stack | No | Yes (with `AUTO_PUSHD`) |
In zsh, enable `AUTO_PUSHD` so every `cd` populates the stack automatically:
```zsh
setopt AUTO_PUSHD # every cd acts like pushd
setopt PUSHD_IGNORE_DUPS # skip duplicates
```
Then `cd -2`, `cd -3` etc. just work.
With oh-my-zsh, `d` shows the directory stack (top 10) and bare numbers `1`–`9` are aliases for `cd -1` through `cd -9`. Also provides `...`=`../..`, `....`=`../../..`, etc.
## Bypassing Aliases, Functions, and Builtins
Three prefixes control how the shell resolves a command name:
| Prefix | Skips | Runs |
|--------|-------|------|
| `\cmd` | aliases | function → builtin → external |
| `command cmd` | aliases + functions | builtin → external |
| `builtin cmd` | aliases + functions + external | builtin only |
```bash
\opencode # skip the alias, run the function/binary
command opencode # skip alias AND any function named opencode
builtin cd /tmp # guaranteed shell builtin, nothing else
```
`builtin` is needed when a function overrides a builtin — e.g. fzf's `cd` function uses `builtin cd` internally to avoid calling itself.
## Writing Output to File
```bash
command > file.txt # overwrite
command >> file.txt # append
command | tee file.txt # overwrite + display
command | tee -a file.txt # append + display
```
**Capture output in a variable:**
```bash
last_output=$(your_command)
echo "$last_output" > output.txt
```
## Functions
- `declare -F` — list all defined function names
- `declare -f` — list all functions with their bodies
---
See also: [[Misc CLI]], [[Nohup]], [[Screen]]