bash-shortening
Rewrite verbose Bash into concise, idiomatic Bash without losing readability.
Skill by paulnsorensen
Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/paulnsorensen-bash-shortening
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Use cases: writing
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.
- Tools
- No tools found
- Secrets
- None asked for
- Install scripts
- None found
- Runs as
- Python package
Network hosts it talks to 1
codeload.github.com· found in install command
Files it touches
~/.claude/skills/bash-shortening
What's inside
- Skill name
bash-shortening- Description
- Rewrite verbose Bash into concise, idiomatic Bash without losing readability. Use when the user says "shorten this script", "make this more idiomatic", "clean up this bash", "this script is too long", "is there a shorter way to do this in bash", asks for a review of a Bash script, or when you write a new Bash `.sh`/`.bash` script or `bash` block. Covers parameter expansion, brace expansion, process substitution, arithmetic, functions, heredocs, associative arrays, parallel jobs, and IFS parsing, and refuses cryptic one-liners. Do NOT use for fish, zsh, or POSIX `/bin/sh` scripts, where bashisms break portability.
- License
- MIT
- Instructions
- 153 lines in SKILL.md · view on GitHub
Before installing
- Ships executable scripts
Files (22)
- AGENTS.md
- SKILL.md
- advanced.md · references/
- anti-patterns.md · references/
- arithmetic.md · references/
- brace-expansion.md · references/
- command-substitution.md · references/
- functions.md · references/
- parameter-expansion.md · references/
- process-substitution.md · references/
- real-world.md · references/
- bash-shorten.py · scripts/
- engine.py · scripts/
- rules.py · scripts/
- backticks.yml · scripts/sg-rules/
- test-numeric-eq.yml · scripts/sg-rules/
- test-numeric-ge.yml · scripts/sg-rules/
- test-numeric-gt.yml · scripts/sg-rules/
- test-numeric-le.yml · scripts/sg-rules/
- test-numeric-lt.yml · scripts/sg-rules/
- test-numeric-ne.yml · scripts/sg-rules/
- sgconfig.yml · scripts/
SKILL.md (first lines)
# bash-shortening
Make Bash scripts shorter without making them harder to read.
The source is 51 techniques from Karandeep Singh's "Bash Code Shortening"
article, kept as a cheatsheet plus categorized references.
## Philosophy
Shortening expresses intent; it does not save keystrokes.
The win is fewer moving parts: subprocesses, temp files, and intermediate variables.
A cryptic `${1:-${X:-${Y/-,/ }}}` chain is worse than three clear lines.
Two questions decide every change:
1. Does the shorter form remove a class of bugs (a forgotten `rm`, a missed branch, a check-then-`mkdir` race)? If yes, shorten.
2. Does the shorter form hide intent from the next reader? If yes, keep it long.
When both fire, prefer clarity.
## Flow
Analyzers gather in parallel; the main thread is the only writer.
Parallel writes to one file race, and category rewrites overlap on the same lines.
1. **Identify the target.** Take file paths, a pasted snippet, or a `bash` block.
Done when the shebang or context confirms Bash (see "When not to use").
2. **Run the analyzer sweep.** Dispatch one read-only analyzer per row of the category table, all in one batched call.
Use any parallel primitive the host has: sub-agents, parallel tool calls, or `parallel`/`xargs -P`.
With no parallel primitive, walk the table in one pass and tick off each row.
Done when every category has a report, including empty ones.
3. **Merge.** Collect the `path:line — verbose → idiomatic` hits.
Keep one entry per line and note every category that flagged it.
4. **Run the rewriter.** From the main thread, run `python3 scripts/bash-shorten.py --apply <file>` once per file.
Paths under `scripts/` and `references/` are relative to this skill's directory.
Never give `--apply` to an analyzer.
5. **Verify.** Run `bash -n <file>`, then `shellcheck <file>` when present, then read the diff.
When a rule gives a surprising result, revert and narrow with `--rules` or `--skip`.
Done when syntax and shellcheck pass and every hunk is expected.
6. **Show the punch list.** Present the analyzer hits the rewriter did not cover.
Let the user pick categories, especially where anti-pattern hits conflict with shortening hits.
7. **Hand-edit.** Apply one technique per change, with its rationale visible.
Use the before/after examples in the matching reference.
Keep quoting, `set -euo pipefail`, and error handling.
Stop before a rewrite needs a comment to explain *what* it does.
**Analyzer brief** (substitute `<category>` and `<target>`):
> Read `references/<category>.md` in the bash-shortening skill directory.
> Scan `<target>` for every pattern it covers.
> Return a markdown list: `path:line — verbose form → idiomatic form`.
> Do not rewrite or write any file, and do not run `scripts/bash-shorten.py`.
> Flag a hit that conflicts with the anti-patterns reference, but still include it.
## Categories
This table is the complete checklist.
A single reviewer tunnels on the first two or three categories; the sweep exists to prevent that.
The article numbers map to the example numbers inside each reference.
| Reference | Article | Patterns to find |
|---|---|---|
| `references/command-substitution.md` | 3-7 | temp files replaced by `$(cmd)` or pipelines, reused output, `xargs`, `find \| xargs` vs process substitution |
| `references/parameter-expansion.md` | 8-15 | `if [ -z "$X" ]` defaults, `cut -c`/`echo \| sed` substitutions, `${#S}`, `basename`/`dirname` |
| `references/functions.md` | 16-20 | repeated logging blocks, default params, echo-returns, named params |
| `references/brace-expansion.md` | 21-26 | sequential `mkdir`/`touch`, literal `for i in 1 2 3` ranges, zero-padded sequences |
| `references/process-substitution.md` | 27-31 | temp files feeding `diff` or loops, `echo x \| cmd` → `<<<` |
| `references/arithmetic.md` | 32-38 | `expr`, `$(…)+1` increments, `[ -gt ]` numeric tests, `[ A ] && [ B ]`, ternary gotcha |
| `references/real-world.md` | 39-45 | config parsing, log analysis, health checks, batch jobs, backups, API + `jq` |
| `references/advanced.md` | 48-51 | repeated `echo` → heredoc, 3+ branch `if` → `case` or assoc array, independent commands → `& wait`, `cut -d,` in loops → `IFS` |
| `references/anti-patterns.md` | 1-2, 46-47 | nested expansions, cryptic one-liners, places where shortening hurts; flag only, never auto-rewrite |
## Rewriter
`scripts/bash-shorten.py` applies the high-confidence rewrites.
It needs no third-party Python packages, but it requires [ast-grep](https://ast-grep.github.io/) (`sg`) on PATH.
It is a dry run by default: it prints a unified diff and per-rule counts.
```bash
python3 scripts/bash-shorten.py script.sh # preview
python3 scripts/bash-shorten.py --apply script.sh # atomic in-place write
python3 scripts/bash-shorten.py --rules backticks,test-numeric script.sh
python3 scripts/bash-shorten.py --skip find-exec-rm-delete script.sh
python3 scripts/bash-shorten.py --include modernize --apply script.sh
python3 scripts/bash-shorten.py --list # rules, groups, article refs
python3 scripts/bash-shorten.py --explain test-numeric
python3 scripts/bash-shorten.py --self-test
```
- **`core`** (default): idiomatic rewrites that keep the same tools.
- **`modernize`** (opt-in): rewrites to `sd`, `rg -F`, and `fd`.
They need those binaries, and `find → fd` changes behavior because `fd` respects `.gitignore`.
- **Opt-out:** a `# bash-shorten: disable` … `# bash-shorten: enable` span, or `# bash-shorten: skip` for the next line, protects code from every rule.
The rewriter cannot do data-flow work: single-use variable inlining, temp-file → pipeline, function extraction, parallelization, or judging whether an `&& … ||` chain is safe.
Those are hand-edits from the references.
When `sg` is missing, the script exits with a diagnostic.
Install it (`brew install ast-grep` or `cargo install ast-grep --bin sg`), or skip the rewriter and run only the analyzer sweep.
To add or change a rule, read `AGENTS.md` first.
## Quick wins
| Verbose form | Idiomatic form | Reference (article #) |
|---|---|---|
| `if [ -z "$X" ]; then X=default; fi` | `X=${X:-default}` | parameter-expansion (8) |
| `$(echo "$S" \| cut -c1-5)` | `${S:0:5}` | parameter-expansion (10) |
| `$(basename "$P")` / `$(dirname "$P")` | `${P##*/}` / `${P%/*}` — hand-edit only: both break on a trailing `/`, and `dirname` returns `.` for a path with no `/` | parameter-expansion (11-12) |
| `$(echo "$S" \| sed 's/a/b/g')` | `${S//a/b}` | parameter-expansion (13-14) |
| `$(echo -n "$S" \| wc -c)` | `${#S}` | parameter-expansion (15) |
| `$(expr $A + $B)` / `C=$(expr $C + 1)` | `$((A + B))` / `((C+=1))` | arithmetic (32-34) |
| `[ $X -gt 100 ]` / `[ $A ] && [ $B ]` | `((X > 100))` / `[[ $A && $B ]]` | arithmetic (35, 37) |
| `mkdir a; mkdir b; mkdir c` | `mkdir -p {a,b,c}` | brace-expansion (21-22) |
| `for i in 1 2 3 4 5` | `for i in {1..5}` (or `{01..10}`, `{2..10..2}`) | brace-expansion (23-26) |
| `cmd > /tmp/x; cmd2 < /tmp/x; rm /tmp/x` | `cmd \| cmd2` or `cmd2 < <(cmd)` — differ from the temp-file form in concurrency, `SIGPIPE` handling, and `pipefail` exit status | command-substitution (5), process-substitution (29) |
| `sort a > /tmp/a; sort b > /tmp/b; diff …` | `diff <(sort a) <(sort b)` | process-substitution (27) |
| `if [ "$E" = dev ]; elif …` (3+ branches) | `case` or `${URLS[$E]:-default}` | functions, advanced (49) |
| Repeated `echo "[$(date)] [LEVEL] msg"` | a `log()` function with `${1^^}` | functions (16) |
| `find … > /tmp/x; while read …; done < /tmp/x` | `done < <(find …)` or `find … \| xargs cmd` | command-substitution (6), process-substitution (29) |
| Many `echo "..."` lines | `cat <<EOF … EOF` | advanced (48) |From paulnsorensen/dotfiles, MIT.
More from paulnsorensen/dotfiles
- 0.603score
bin-doctor
paulnsorensen
Audit and repair installed binaries so each tool has one install path, a clean cache, and a current pin, across mise, Homebrew, cargo, uv, npm, pnpm, bun…
SkillAFreshness: A★ 2Claude Code +9 - 0.603score
chezmoi
paulnsorensen
Guides dotfile management with chezmoi when the user says "set up dotfiles", "manage my dotfiles", "bootstrap a new machine", "chezmoi", "encrypt my SSH key…
SkillAFreshness: A★ 2Claude Code +9 - 0.603score
build-optimize
paulnsorensen
Optimize local build, test, and check commands with measured wall-time evidence.
SkillAFreshness: A★ 2Claude Code +9 - 0.600score
ci-optimize
paulnsorensen
Optimize GitHub Actions workflow wait time with measured evidence.
SkillAFreshness: A★ 2Claude Code +9 - 0.598score
cheese-board-loop
paulnsorensen
Runs the cheese-board workflow and asks the user each question it raises.
SkillAFreshness: A★ 2Claude Code +9 - 0.557score
spec-verify
paulnsorensen
Verify a spec's implementation against its requirements using Serena structural analysis, build verification, and test coverage.
SkillBFreshness: B★ 2Claude Code +9 - 0.507score
grok-codebase
paulnsorensen
Use when the user wants deep, multi-session internalization of an unfamiliar codebase — not just an orientation, but the goal of being able to explain it on a…
SkillCFreshness: C★ 2Claude Code +9 - 0.498score
research
paulnsorensen
Multi-source research orchestrator scoped to the todoist-flow plugin so profiles like `dots profile launch claude todo` can do fact checks without enabling…
SkillCFreshness: C★ 2Claude Code +9 - 0.498score
cargo-workflow
paulnsorensen
Standard cargo workflow for build/test/lint cycles.
SkillCFreshness: C★ 2Claude Code +9 - 0.482score
tour
paulnsorensen
Use when the user wants a quick, single-session read-only tour of an unfamiliar codebase or a specific feature — orientation, not memorization.
SkillCFreshness: C★ 2Claude Code +9 - 0.482score
read-mode-probe
paulnsorensen
Use when the user wants to interrogate an unfamiliar codebase with structured probes rather than a summary — invariants, data flow, error paths, hot paths…
SkillCFreshness: C★ 2Claude Code +9 - 0.482score
design-doc
paulnsorensen
Use when the user wants to draft, revise, critique, or shepherd a design document, RFC, ADR, tech spec, or design proposal.
SkillCFreshness: C★ 2Claude Code +9
Signals
- Stars
- 2
- Forks
- 0
- Open issues
- 69
- Last commit (this folder)
- Sep 24, 2026 (1 month ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- MIT
- Repository
- github.com/paulnsorensen/dotfiles
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from paulnsorensen
- 0.603score
build-optimize
paulnsorensen
Optimize local build, test, and check commands with measured wall-time evidence.
SkillAFreshness: A★ 2Claude Code +9 - 0.603score
chezmoi
paulnsorensen
Guides dotfile management with chezmoi when the user says "set up dotfiles", "manage my dotfiles", "bootstrap a new machine", "chezmoi", "encrypt my SSH key…
SkillAFreshness: A★ 2Claude Code +9 - 0.603score
bin-doctor
paulnsorensen
Audit and repair installed binaries so each tool has one install path, a clean cache, and a current pin, across mise, Homebrew, cargo, uv, npm, pnpm, bun…
SkillAFreshness: A★ 2Claude Code +9 - 0.600score
ci-optimize
paulnsorensen
Optimize GitHub Actions workflow wait time with measured evidence.
SkillAFreshness: A★ 2Claude Code +9 - 0.598score
cheese-board-loop
paulnsorensen
Runs the cheese-board workflow and asks the user each question it raises.
SkillAFreshness: A★ 2Claude Code +9 - 0.592score
skillz
paulnsorensen
Add, improve, audit, wedge, or autoimprove a skill.
SkillAFreshness: A★ 1Claude Code +9
Cite this page
bash-shortening skill. Agent Mart. https://agentmart.dev/skills/paulnsorensen-bash-shortening (last updated 2026-10-24)