Shell style guide
My agent skills
npx -y skills add chenwei791129/agent-skills --skill shell-style-guideAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Review shell/bash code for adherence to Google Shell Style Guide. Use when the user requests a code review of shell scripts (.sh, .bash), writing new shell scripts, fixing shell script issues, or checking shell code against style guidelines. Trigger phrases include: review this shell script, check shell style, write a bash script, review my shell code, or any task involving shell/bash scripting where code quality and consistency matter.
SKILL.md
4.4 KB, as published. Nobody here has run it
Shell Style Guide
Review and write shell scripts following the Google Shell Style Guide.
When Writing Shell Scripts
Use Bash Only
- Use
#!/bin/bashwith minimal flags - Set shell options via
setrather than shebang flags (e.g.,set -o errexit,set -o nounset) - Caution:
(( ))evaluating to zero returns non-zero, which causes exit underset -e - If a script exceeds ~100 lines or has complex control flow, recommend rewriting in Python or Go
File Conventions
- Executables: no extension (strongly preferred) or
.sh - Libraries (sourced only):
.shextension, not executable - SUID/SGID: forbidden — use
sudoinstead
Error Output
Direct all error messages to STDERR:
err() {
echo "[$(date +'%Y-%m-%dT%H:%M:%S%z')]: $*" >&2
}
Review Checklist
When reviewing shell code, check these categories in order:
- Critical bugs — unquoted variables, missing error handling, unsafe
eval - Formatting — 2-space indent, 80-char line limit, pipeline style
- Naming — lowercase_with_underscores for functions/variables, UPPER_CASE for constants
- Best practices —
[[ ]]over[ ],$(cmd)over backticks, arrays over space-delimited strings - Structure —
mainfunction pattern, functions grouped at top, comments on non-obvious logic
For detailed rules and examples in each category, see references/style-rules.md.
Key Rules Summary
Formatting
- Indent: 2 spaces, no tabs
- Line length: max 80 characters
- Pipelines: one-liners stay on one line; multi-segment pipelines split with
|on newline - Loops/conditionals:
; then/; doon same line asif/for/while
Quoting & Variables
- Always quote strings with variables, command substitutions, spaces, or metacharacters
- Prefer
"${var}"over"$var"(exception: single-char specials like$?,$!,$@don't need braces) - Use
"$@"over$*
Features
[[ ... ]]over[ ... ]— avoids pathname expansion and word splitting$(command)over backticks — cleaner nesting(( ... ))for arithmetic — neverlet,$[ ], orexpr- Use arrays for lists — avoid space-delimited strings
- Avoid
eval— use safer alternatives - Use process substitution
< <(cmd)orreadarrayinstead of piping towhile - Use ShellCheck to catch common bugs
Naming
| Element | Convention | Example |
|---|---|---|
| Functions | lower_snake_case | get_user_name() |
| Variables | lower_snake_case | local user_name |
| Constants | UPPER_SNAKE_CASE | readonly MAX_RETRIES=3 |
| Package separator | :: | mypackage::my_func() |
Structure
#!/bin/bash
# File header comment describing the script's purpose.
# Set shell options instead of using shebang flags.
# Note: set -e causes (( )) returning 0 to exit. Use with caution.
# Constants
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Functions (grouped together, before main)
parse_args() { ... }
validate_input() { ... }
main() {
parse_args "$@"
validate_input
# ...
}
main "$@"
Local Variables
- Declare with
localin functions - Separate declaration from assignment when capturing command output:
# Correct — exit code is checkable
local my_var
my_var="$(my_func)"
# Wrong — local always returns 0, masking errors
local my_var="$(my_func)"
Return Values & Pipelines
- Always check return values
- For pipelines, check
PIPESTATUSimmediately (it resets on next command):
tar -cf - ./* | gzip > archive.tar.gz
if (( PIPESTATUS[0] != 0 || PIPESTATUS[1] != 0 )); then
err "Pipeline failed"
fi
Builtins Over External Commands
Prefer shell builtins for efficiency:
# Prefer
addition=$(( x + y ))
[[ "${input}" =~ ^[0-9]+$ ]]
"${str##*/}" # basename
# Avoid
addition=$(expr "${x}" + "${y}")
echo "${input}" | grep -q '^[0-9]+$'
"$(basename "${str}")"