Guidelines and patterns for writing bash/shell scripts. Use when creating new shell scripts, bin scripts, or bash utilities. Includes script templates, header comments, error handling, and common patterns.
Scanned 2/10/2026
Install via CLI
openskills install majiayu000/claude-skill-registry---
name: coding-shell-scripts
description: Guidelines and patterns for writing bash/shell scripts. Use when creating new shell scripts, bin scripts, or bash utilities. Includes script templates, header comments, error handling, and common patterns.
---
# Coding Shell Scripts
## Overview
This skill provides templates and patterns for writing bash scripts. Choose the appropriate template based on your needs:
- **Simple Script Structure**: For straightforward utilities and single-purpose tools
- **Full Script Template**: For complex scripts needing logging, cleanup handlers, and robust error handling
## Simple Script Structure
For straightforward scripts (utilities, single-purpose tools):
```bash
#!/usr/bin/env bash
main() {
# Script logic here
local arg="$1"
if [ -z "$arg" ]; then
echo "Usage: $(basename "$0") <argument>" >&2
exit 1
fi
# Do the work
echo "Processing: $arg"
}
main "$@"
```
**Important:** Standalone scripts MUST use `exit` (not `return`) for error codes, since they run in their own process.
## Full Script Template
For more complex scripts with logging, cleanup, and robust error handling:
```shell
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
# Normalize TMPDIR (strip trailing slash for consistent path construction)
TMPDIR="${TMPDIR:-/tmp}"
TMPDIR="${TMPDIR%/}"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
#/ Usage:
#/ Description:
#/ Examples:
#/ Options:
#/ --help: Display this help message
usage() { grep '^#/' "$0" | cut -c4- ; exit 0 ; }
expr "$*" : ".*--help" > /dev/null && usage
readonly LOG_FILE="${TMPDIR}/$(basename "$0").log"
_print() {
case "$1" in
black) color="30" ;; red) color="31" ;; green) color="32" ;;
yellow) color="33" ;; blue) color="34" ;; magenta) color="35" ;;
cyan) color="36" ;; white) color="37" ;;
*) echo "Unknown color: $1" >&2; return 1 ;;
esac
shift
while [ "$#" -gt 1 ]; do
case "$1" in
bold) color="${color};1" ;; dim) color="${color};2" ;;
*) echo "Unknown option: $1" >&2; return 1 ;;
esac
shift
done
supported_colors=$(tput colors 2>/dev/null || echo 0)
if [ -n "$supported_colors" ] && [ "$supported_colors" -gt 8 ]; then
printf "\\033[${color}m%b\\033[0m\\n" "$1"
else
printf "%b\n" "$1"
fi
}
info() { _print cyan "info $@" | tee -a "$LOG_FILE" >&2 ; }
warning() { _print yellow "warning $@" | tee -a "$LOG_FILE" >&2 ; }
error() { _print red "error $@" | tee -a "$LOG_FILE" >&2 ; }
fatal() { _print red bold "fatal $@" | tee -a "$LOG_FILE" >&2 ; exit 1 ; }
cleanup() {
# Remove temporary files
# Restart services
# ...
}
if [[ "${BASH_SOURCE[0]}" = "$0" ]]; then
trap cleanup EXIT
# Script goes here
# ...
fi
```
## Script Validation
**CRITICAL: Always validate shell scripts after creating or editing them.**
### Required Validation Steps
After creating or editing any shell script, you MUST run both validation tools:
1. **Syntax Check with bash -n**
```shell
bash -n script.sh
```
Catches basic syntax errors:
- Missing closing quotes
- Unmatched brackets or braces
- Invalid command syntax
2. **Static Analysis with shellcheck**
```shell
shellcheck script.sh
```
Catches deeper issues:
- Quoting problems (word splitting, glob expansion)
- Deprecated or unsafe syntax
- Common bugs and anti-patterns
- Unused or misspelled variables
- Portability issues
### Validation Pattern
Run both checks together:
```shell
bash -n script.sh && shellcheck script.sh
```
Only consider the script complete after both tools pass without errors.
### Handling Shellcheck Warnings
When shellcheck warnings are intentional, disable them with directives:
```shell
# Disable specific warning for one line
# shellcheck disable=SC2086
echo $unquoted_on_purpose
# Disable multiple codes for entire file (at top)
# shellcheck disable=SC2086,SC2181
# Document why you're disabling
# We want word splitting here for argument passing
# shellcheck disable=SC2086
command $args
```
**Common codes you might need to disable:**
- `SC2086`: Word splitting/globbing (when intentional for argument passing)
- `SC2181`: Testing `$?` explicitly (when needed for clarity)
- `SC1090`: Dynamic source paths (shellcheck can't follow them)
- `SC2034`: Unused variables (e.g., when reading into multiple vars)
**Important:** Only disable shellcheck warnings when you understand why they're triggered and have a valid reason to ignore them. Document your reasoning in comments.
## Bash Constructs
**`for`**
```shell
for i in ( ls some-directory ); do
echo $i
done
SomeArray=("foo" "bar" "baz")
for item in ${SomeArray[*]}; do
echo $item
done
```
**`case`**
```shell
case "$variable" in
abc) echo "\$variable = abc" ;;
xyz) echo "\$variable = xyz" ;;
esac
```
**`ln`**
```shell
ln -s <real_file> <future_link>
```
**`select`**
```shell
select result in Yes No Cancel
do
echo $result
done
```
**`tput`**
```shell
tput cuu1 # Move cursor up by one line
tput el # Clear the line
```
## Common Patterns
**Ternary expressions**
```shell
<expression> && <on-true expression> || <on-false expression>
# See below example for file/stdin to variable.
```
**File or stdin assignment**
Assign either a file or stdin (piped input) to a variable, with fallbacks:
```shell
# Use a filepath from args when available, or use stdin
[ $# -ge 1 -a -f "$1" ] && input="$1" || input="-"
content=$(cat $input)
# Use stdin if pipe is occupied, otherwise use a file
(test -s /dev/stdin) && input="-" || input="./config.json"
content=(cat $input)
```
## Arithmetic Operations
Use `(())` for arithmetic:
```shell
echo $(( 5 - 1 ))
```
## CLI Arguments
More involved: https://medium.com/@Drew_Stokes/bash-argument-parsing-54f3b81a6a8f
```shell
# Simple double dash arg
arg_no_bump="false"
expr "$*" : ".*--no-bump" > /dev/null && arg_no_bump="true"
```
## Reference Links
http://tldp.org/LDP/abs/html/index.html
https://stackoverflow.com/documentation/bash/topics
https://dev.to/thiht/shell-scripts-matter
No comments yet. Be the first to comment!