---
title: "Bash One-Liners Cheatsheet"
slug: "bash-one-liners"
category: "cheatsheets"
tags: ["cheatsheets", "bash", "shell", "reference", "cli"]
status: "stable"
last_updated: 2026-05-14
summary: "Useful bash one-liners with the why next to the what: find and replace, file discovery, jobs and traps, parameter expansion, arithmetic."
related:
  [
    "[[coding/shell]]",
    "[[cheatsheets/git-commands]]",
    "[[cheatsheets/regex-patterns]]",
    "[[file-organization/dotfiles]]",
    "[[cheatsheets/index|Cheatsheets]]",
  ]
---

## Overview

Bash carries a lot of weight in day-to-day plumbing. This card collects the one-liners worth memorizing, grouped by task. The full rules (`set -euo pipefail`, quoting, error handling) live in [[coding/shell]]; this page is the lookup table for "what was that flag again?". All examples assume Bash 5 with `set -euo pipefail`.

## Find files

Find before rename, find before delete, find before pipe.

| One-liner                                    | What it does                                 |
| -------------------------------------------- | -------------------------------------------- |
| `find . -type f -name '*.md'`                | All markdown files, recursive.               |
| `find . -type f -newer reference.txt`        | Files modified after `reference.txt`.        |
| `find . -type f -size +10M`                  | Files larger than 10 MB.                     |
| `find . -type f -mtime -7`                   | Files modified in the last 7 days.           |
| `find . -type f -name '*.log' -delete`       | Delete matched files in one pass.            |
| `find . -type f -name '*.tmp' -exec rm {} +` | Same, batched for fewer `rm` calls.          |
| `find . -type d -empty -delete`              | Prune empty directories.                     |
| `grep -rIn "pattern" .`                      | Recursive grep, line numbers, skip binaries. |
| `rg -n "pattern"`                            | ripgrep; faster and respects `.gitignore`.   |

Use `find ... -print0 \| xargs -0` when filenames may contain spaces or newlines.

## Find and replace

In-place edits should be staged in git first.

| One-liner                                             | What it does                              |
| ----------------------------------------------------- | ----------------------------------------- |
| `sed -i 's/old/new/g' file.txt`                       | GNU sed in-place replacement (Linux).     |
| `sed -i '' 's/old/new/g' file.txt`                    | BSD sed in-place replacement (macOS).     |
| `find . -name '*.md' -exec sed -i 's/old/new/g' {} +` | Replace across many files.                |
| `grep -rl "old" . \| xargs sed -i 's/old/new/g'`      | Replace only in files that contain "old". |
| `tr 'A-Z' 'a-z' < file > lower.txt`                   | Lowercase a file.                         |
| `awk '{print $2, $1}' file`                           | Swap columns 1 and 2.                     |

`sed -i` differs between BSD and GNU. Write `sed -i.bak` and keep the backup for portability.

## Parameter expansion

The shell offers cheap string ops; reach for these before sed.

| Expansion                | Result for `f=path/to/file.tar.gz`                |
| ------------------------ | ------------------------------------------------- |
| `${f##*/}`               | `file.tar.gz` (basename).                         |
| `${f%/*}`                | `path/to` (dirname).                              |
| `${f%.*}`                | `path/to/file.tar` (drop last extension).         |
| `${f%%.*}`               | `path/to/file` (drop all extensions).             |
| `${f#*.}`                | `tar.gz` (drop everything up to the first dot).   |
| `${f//\//-}`             | `path-to-file.tar.gz` (replace all `/` with `-`). |
| `${name:-default}`       | Use `default` if `name` unset or empty.           |
| `${name:?error message}` | Exit with an error if `name` is unset.            |
| `${#name}`               | Length of `name`.                                 |

Pure-bash string ops avoid forking a subprocess; in tight loops the win is real.

## Jobs and traps

Background work needs cleanup; traps make cleanup unconditional.

| One-liner                               | What it does                                  |
| --------------------------------------- | --------------------------------------------- |
| `cmd &`                                 | Run in background.                            |
| `jobs`                                  | List background jobs in this shell.           |
| `wait`                                  | Block until all background jobs finish.       |
| `wait $PID`                             | Block until one specific PID exits.           |
| `disown %1`                             | Detach job 1 from the shell; survives logout. |
| `trap 'rm -rf "$TMP"' EXIT`             | Cleanup runs on normal and abnormal exit.     |
| `trap 'echo interrupted; exit 130' INT` | Custom handler for Ctrl-C.                    |
| `nohup cmd > out.log 2>&1 &`            | Detach from controlling terminal.             |

Always trap `EXIT` for temp-directory cleanup. Use `mktemp -d` to create the directory.

## Arithmetic and tests

Bash arithmetic is integer-only; use `bc` or `awk` for floats.

| One-liner                   | What it does                        |
| --------------------------- | ----------------------------------- |
| `(( count++ ))`             | Increment in arithmetic context.    |
| `echo $(( 3 * (4 + 5) ))`   | Inline arithmetic; prints 27.       |
| `echo "scale=2; 7/3" \| bc` | Float division; prints 2.33.        |
| `[[ -f file ]]`             | True if file exists and is regular. |
| `[[ -d dir ]]`              | True if directory exists.           |
| `[[ -z $var ]]`             | True if variable is empty or unset. |
| `[[ $a == "yes" ]]`         | String equality.                    |
| `[[ $s =~ ^[0-9]+$ ]]`      | Regex match; numeric string.        |

Prefer `[[ ... ]]` over `[ ... ]`. It does not split words, does pattern and regex matching, and does not need quoting around variables.

## Common gotchas

- Unquoted variables word-split. Write `"$var"` everywhere unless you intentionally want splitting.
- `cd /tmp/$dir` fails silently if `cd` fails. Write `cd "$dir" \|\| exit 1` or run with `set -e`.
- Pipelines hide exit codes from earlier commands. `set -o pipefail` fixes it.
- `for f in *.md` returns the literal `*.md` if nothing matches. Set `shopt -s nullglob` first.
- `read` strips leading and trailing whitespace and interprets backslashes. Use `read -r line` for raw input.
- `$(...)` and backticks both subshell out. Prefer `$(...)`; it nests and quotes cleanly.

## Related

- [[coding/shell]]
- [[cheatsheets/git-commands]]
- [[cheatsheets/regex-patterns]]
- [[file-organization/dotfiles]]
- [[cheatsheets/index|Cheatsheets]]
