shell-scripts
Skill3 starsChanged 8 months agoMITView on GitHub
POSIX-compatible shell scripting guide based on Google Shell Style Guide. Use when writing, editing, or reviewing shell scripts (.sh), bash scripts, automation scripts, or any executable script files. Triggers on #!/bin/sh, #!/bin/bash, .sh file creation, shell function definitions, or shell scripting questions.
- Deletes or force-pushes
3 other projects use a version of this.
Adopted by
Most recently taken up by
- profdorly/ultimate-dev-skillstheir own version, first seen Nov 8, 2026
- hiromaily/go-crypto-wallettheir own version, first seen Oct 9, 2026
- masonhuemmer/dopsword for word, first seen Mar 24, 2026
Other versions3 projects use a version of this.
Word for word · 1
- masonhuemmer/dops★ 3100% same
Edited · 0
None found.
Wrote their own version · 2
- hiromaily/go-crypto-wallet★ 128same name
- profdorly/ultimate-dev-skills★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository19 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- bubbletea-patternsSkill
- charm-stylingSkill
- clean-code-boundariesSkill
- clean-code-designSkill
- clean-code-errorsSkill
- clean-code-functionsSkill
- clean-code-namingSkill
- clean-code-solidSkill
- clean-code-testingSkill
- cli-structureSkill
- create-runbookSkill
- demo-recordingSkill
- mutation-testingSkill
- spec-workflowSkill
- tdd-workflowSkill
- tui-layoutSkill
- tui-testingSkill
- wizard-formsSkill
The file
We split this skill into the rules it gives an agent
1 rule. About 0 are common, 1 is distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 15
Only use bash/zsh when you need specific features.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Shell Script Style Guide
Based on https://google.github.io/styleguide/shellguide.html with POSIX compatibility as the default.
Shell Selection
Default to POSIX sh (#!/bin/sh) for cross-platform compatibility (Linux + macOS).
Only use bash/zsh when you need specific features. If you do, add a comment explaining why:
#!/bin/bash
# Requires bash for: associative arrays, process substitution, [[ ]]When to use each shell
| Shell | Shebang | Use when |
| POSIX sh | #!/bin/sh | Default. Simple scripts, CI/CD, Docker, automation |
| Bash | #!/bin/bash | Need arrays, [[ ]], ${var//pat/rep}, process substitution |
| Zsh | #!/bin/zsh | Need zsh-specific features (glob qualifiers, associative arrays with special syntax) |
POSIX vs Bash quick reference
| Feature | POSIX (sh) | Bash |
| Test | [ -n "$var" ] | [[ -n "$var" ]] |
| String replace | echo "$var" | sed 's/a/b/' | ${var//a/b} |
| Arrays | Not available | arr=(a b c) |
| Local vars | var=value (function scope) | local var=value |
| Arithmetic | $(( x + 1 )) | $(( x + 1 )) ✓ same |
| Command check | command -v foo | command -v foo ✓ same |
| Here strings | Not available | <<< "string" |
| Pipefail | Not available | set -o pipefail |
| Read -r | read -r var ✓ | read -r var ✓ same |
File Header
#!/bin/sh
#
# Brief description of what the script does.
#
# Usage:
# ./script.sh [options]
#Error Handling
#!/bin/sh
set -eu
# Trap for cleanup on exit
cleanup() {
rm -f "${TMPFILE:-}"
}
trap cleanup EXITDo NOT use set -o pipefail — it's not POSIX. If you need pipefail, switch to bash and document why.
Variables
# Use uppercase for exported/environment variables
ENDPOINT="${ENDPOINT:?endpoint is required}"
DRY_RUN="${DRY_RUN:-false}"
TIMEOUT="${TIMEOUT:-30}"
# Use lowercase for local script variables
output_dir="/tmp/results"
log_file="${output_dir}/run.log"Always quote variables: "${var}" not $var
Use ${var:?message} for required variables — fails with message if unset/empty.
Use ${var:-default} for optional variables with defaults.
Functions
# Lowercase with underscores. Short and focused.
check_dependency() {
if ! command -v "$1" > /dev/null 2>&1; then
echo "Error: $1 is not installed" >&2
return 1
fi
}
# Document complex functions
#
# Validates the input configuration file.
#
# Args:
# $1 - Path to config file
# Returns:
# 0 on success, 1 on validation error
validate_config() {
config_file="$1"
if [ ! -f "${config_file}" ]; then
echo "Error: config file not found: ${config_file}" >&2
return 1
fi
}
# Put main at the bottom
main() {
check_dependency "curl"
check_dependency "jq"
validate_config "${CONFIG_FILE}"
# ...
}
main "$@"Conditionals
# POSIX test — use [ ] not [[ ]]
if [ -n "${var}" ]; then
echo "var is set"
fi
if [ "${status}" -eq 0 ]; then
echo "success"
fi
# String comparison
if [ "${env}" = "production" ]; then
echo "deploying to prod"
fi
# File tests
if [ -f "${path}" ]; then echo "file exists"; fi
if [ -d "${path}" ]; then echo "directory exists"; fi
if [ -x "${path}" ]; then echo "is executable"; fi
# Negation
if [ ! -f "${path}" ]; then echo "file missing"; fi
# AND / OR
if [ -n "${var}" ] && [ -f "${path}" ]; then
echo "both conditions met"
fiLoops
# Iterate over arguments
for arg in "$@"; do
echo "Processing: ${arg}"
done
# Iterate over command output
for file in $(find /tmp -name "*.log" -type f); do
echo "Found: ${file}"
done
# While loop with read (POSIX safe)
while IFS= read -r line; do
echo "Line: ${line}"
done < "${input_file}"
# Counter loop
i=0
while [ "${i}" -lt 10 ]; do
echo "Iteration: ${i}"
i=$((i + 1))
doneOutput
# Normal output to stdout
echo "Processing..."
# Errors to stderr
echo "Error: file not found" >&2
# Formatted output — use printf for portability
printf "%-20s %s\n" "Name:" "${name}"
printf "Status: %d\n" "${exit_code}"
# DO NOT use echo -e (not portable)
# Bad: echo -e "line1\nline2"
# Good: printf "line1\nline2\n"Temporary Files
# Use mktemp for secure temp files
TMPFILE=$(mktemp)
TMPDIR=$(mktemp -d)
# Always clean up
trap 'rm -f "${TMPFILE}"; rm -rf "${TMPDIR}"' EXITCommand Substitution
# Use $() not backticks
result=$(date +%Y-%m-%d)
count=$(wc -l < "${file}")
# Nested substitution
path=$(dirname $(readlink -f "$0"))Arithmetic
# POSIX arithmetic
total=$((count + 1))
half=$((total / 2))
# Comparison in conditions
if [ "${count}" -gt 10 ]; then
echo "many items"
fiCommon Patterns
Check if command exists
if ! command -v docker > /dev/null 2>&1; then
echo "Error: docker is required" >&2
exit 1
fiParse simple flags
verbose=false
dry_run=false
while [ $# -gt 0 ]; do
case "$1" in
-v|--verbose) verbose=true ;;
-n|--dry-run) dry_run=true ;;
*) echo "Unknown option: $1" >&2; exit 1 ;;
esac
shift
doneRetry with backoff
retry() {
max_attempts="$1"
shift
attempt=1
while [ "${attempt}" -le "${max_attempts}" ]; do
if "$@"; then
return 0
fi
echo "Attempt ${attempt}/${max_attempts} failed, retrying..." >&2
sleep "$((attempt * 2))"
attempt=$((attempt + 1))
done
return 1
}
retry 3 curl -sf "https://example.com/health"JSON processing with jq
# Extract a field
name=$(echo "${json}" | jq -r '.name')
# Check if jq is available, fall back to grep
if command -v jq > /dev/null 2>&1; then
status=$(echo "${response}" | jq -r '.status')
else
status=$(echo "${response}" | grep -o '"status":"[^"]*"' | cut -d'"' -f4)
fiThings to Avoid
| Avoid | Use instead | Why |
#!/bin/bash (default) | #!/bin/sh | POSIX portability |
[[ ]] | [ ] | Not POSIX |
echo -e | printf | Not portable |
which | command -v | Not POSIX guaranteed |
$var unquoted | "${var}" | Word splitting, globbing |
Backticks `cmd` | $(cmd) | Nesting, readability |
set -o pipefail | error check per pipe | Not POSIX |
local -r | local or plain var | -r not POSIX with local |
{a,b,c} | explicit list | Brace expansion not POSIX |
source file | . file | source not POSIX |
function foo() | foo() | function keyword not POSIX |
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

