Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Shell scripting best practices and patterns. Use when writing bash/zsh scripts, automating tasks, creating CLI tools, or debugging shell commands.
.claude/skills/aiskillstore-shell-scripting/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 21% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 1% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 276% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 36% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 54% | 0% |
Expert guidance for writing robust, maintainable Bash and Zsh scripts with best practices for automation and command-line tool usage.
Start every script with:
bash#!/usr/bin/env bash set -euo pipefail IFS=$'\n\t'
set -e: Exit on errorset -u: Error on undefined variablesset -o pipefail: Catch errors in pipesIFS=$'\n\t': Safer word splitting"$variable" not $variable[[ for conditionals (Bash): if [[ "$var" == "value" ]]; thenif command -v git &> /dev/null; thenls: Use globs or find insteadfiles=("file1" "file2") not space-separated stringsbash trap cleanup EXIT trap 'echo "Error on line $LINENO"' ERR
bashwhile [[ $# -gt 0 ]]; do case $1 in -h|--help) usage; exit 0 ;; -v|--verbose) VERBOSE=true; shift ;; -*) echo "Unknown option: $1"; exit 1 ;; *) break ;; esac done
bash# Prefer this (handles spaces, newlines correctly): while IFS= read -r -d '' file; do echo "Processing: $file" done < <(find . -type f -name "*.txt" -print0) # Or with simple globs: for file in *.txt; do [[ -e "$file" ]] || continue # Skip if no matches echo "Processing: $file" done
bashread -rp "Continue? [y/N] " response if [[ "$response" =~ ^[Yy]$ ]]; then echo "Continuing..." fi
bashRED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color echo -e "${GREEN}Success${NC}" echo -e "${RED}Error${NC}" >&2
When appropriate, suggest these modern replacements:
ripgrep (rg) → faster than grepfd → faster than findfzf → interactive filteringjq → JSON processingyq → YAML processingbat → cat with syntax highlightingeza → enhanced lsbashusage() { cat <<EOF Usage: ${0##*/} [OPTIONS] <args> Description of what this script does. OPTIONS: -h, --help Show this help -v, --verbose Verbose output EOF } main() { # Main logic here : }
When user specifies Zsh:
**/*.txt (recursive), *.txt~*test* (exclude pattern)${var:u} (uppercase), ${var:l} (lowercase)typeset -A hash; hash[key]=valuesetopt extended_globeval untrusted inputmktemp for temporary files: TEMP_FILE=$(mktemp)rm -rf operations[[ ]] vs test, $(( )) vs expr)var=$(cat file) → var=$(<file)read not cat | while: while read -r line; do ... done < filexargs -P or GNU parallel for parallel processingSee references/template.sh for a complete, production-ready script template with all best practices incorporated.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 17,373 | 23,185 | +33% | 1 | 1 | 0% | 2,801 | 3,393 | +21% | 0 | 0 | — |
case-02 | pass→pass | 13,463 | 7,704 | -43% | 1 | 1 | 0% | 1,512 | 2,051 | +36% | 0 | 0 | — |
case-03 | pass→pass | 7,494 | 5,364 | -28% | 1 | 1 | 0% | 1,282 | 1,977 | +54% | 0 | 0 | — |
case-04 | pass→pass | 7,872 | 4,966 | -37% | 1 | 1 | 0% | 1,356 | 1,917 | +41% | 0 | 0 | — |
case-05 | pass→pass | 9,606 | 6,109 | -36% | 1 | 1 | 0% | 1,648 | 2,098 | +27% | 0 | 0 | — |
case-06 | pass→pass | 9,815 | 7,289 | -26% | 1 | 1 | 0% | 1,643 | 2,308 | +40% | 0 | 0 | — |
case-07 | pass→pass | 14,947 | 15,699 | +5% | 1 | 1 | 0% | 2,490 | 3,651 | +47% | 0 | 0 | — |
case-08 | fail→pass | 14,854 | 8,917 | -40% | 1 | 1 | 0% | 2,624 | 2,657 | +1% | 0 | 0 | — |
case-09 | pass→pass | 6,332 | 6,047 | -5% | 1 | 1 | 0% | 1,087 | 2,020 | +86% | 0 | 0 | — |
case-10 | pass→pass | 7,161 | 4,680 | -35% | 1 | 1 | 0% | 1,284 | 1,894 | +48% | 0 | 0 | — |
case-11 | pass→pass | 12,221 | 7,696 | -37% | 1 | 1 | 0% | 1,872 | 2,280 | +22% | 0 | 0 | — |
case-12 | pass→pass | 6,070 | 7,503 | +24% | 1 | 1 | 0% | 940 | 2,237 | +138% | 0 | 0 | — |
case-13 | pass→pass | 7,261 | 7,237 | -0% | 1 | 1 | 0% | 1,227 | 2,204 | +80% | 0 | 0 | — |
case-14 | pass→pass | 15,478 | 8,182 | -47% | 1 | 1 | 0% | 2,703 | 2,336 | -14% | 0 | 0 | — |
case-15 | fail→pass | 5,050 | 5,441 | +8% | 1 | 1 | 0% | 506 | 1,904 | +276% | 0 | 0 | — |
case-16 | pass→pass | 7,572 | 6,008 | -21% | 1 | 1 | 0% | 1,235 | 2,059 | +67% | 0 | 0 | — |
case-17 | pass→pass | 7,224 | 6,459 | -11% | 1 | 1 | 0% | 1,308 | 2,061 | +58% | 0 | 0 | — |
case-18 | pass→pass | 6,711 | 3,862 | -42% | 1 | 1 | 0% | 1,018 | 1,691 | +66% | 0 | 0 | — |
case-19 | pass→pass | 10,248 | 7,961 | -22% | 1 | 1 | 0% | 1,617 | 2,300 | +42% | 0 | 0 | — |
case-20 | pass→pass | 5,425 | 4,754 | -12% | 1 | 1 | 0% | 1,011 | 1,889 | +87% | 0 | 0 | — |
case-21 | pass→pass | 10,966 | 12,205 | +11% | 1 | 1 | 0% | 1,916 | 3,168 | +65% | 0 | 0 | — |
case-22 | pass→pass | 4,886 | 4,827 | -1% | 1 | 1 | 0% | 846 | 1,887 | +123% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +14 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.