| name | shell-scripting |
| description | Shell scripting best practices and patterns. Use when writing bash/zsh scripts, automating tasks, creating CLI tools, or debugging shell commands. |
| author | Joseph OBrien |
| status | unpublished |
| updated | 2025-12-23 |
| version | 1.0.1 |
| tag | skill |
| type | skill |
Shell Scripting
Comprehensive shell scripting skill covering bash/zsh patterns, automation, error handling, and CLI tool development.
When to Use This Skill
- Writing automation scripts
- Creating CLI tools
- System administration tasks
- Build and deployment scripts
- Log processing and analysis
- File manipulation and batch operations
- Cron jobs and scheduled tasks
Script Structure
Template
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")"
VERBOSE=false
DRY_RUN=false
usage() {
cat <<EOF
Usage: $SCRIPT_NAME [options] <argument>
Options:
-h, --help Show this help message
-v, --verbose Enable verbose output
-n, --dry-run Show what would be done
EOF
}
log() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*" >&2
}
error() {
log "ERROR: $*"
exit 1
}
main() {
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
usage
exit 0
;;
-v|--verbose)
VERBOSE=true
shift
;;
-n|--dry-run)
DRY_RUN=true
shift
;;
*)
break
;;
esac
done
}
main "$@"
Error Handling
Set Options
set -e
set -u
set -o pipefail
set -x
Trap for Cleanup
cleanup() {
rm -f "$TEMP_FILE"
log "Cleanup complete"
}
trap cleanup EXIT
trap 'error "Script interrupted"' INT TERM
Error Checking Patterns
command -v jq >/dev/null 2>&1 || error "jq is required but not installed"
[[ -f "$FILE" ]] || error "File not found: $FILE"
[[ -d "$DIR" ]] || mkdir -p "$DIR"
[[ -n "${VAR:-}" ]] || error "VAR is not set"
if ! some_command; then
error "some_command failed"
fi
Variables & Substitution
Variable Expansion
${VAR:-default}
${VAR:=default}
${VAR:+value}
${VAR:?error msg}
${VAR#pattern}
${VAR##pattern}
${VAR%pattern}
${VAR%%pattern}
${VAR/old/new}
${VAR//old/new}
${#VAR}
Arrays
declare -a ARRAY=("one" "two" "three")
echo "${ARRAY[0]}"
echo "${ARRAY[@]}"
echo "${#ARRAY[@]}"
echo "${!ARRAY[@]}"
for item in "${ARRAY[@]}"; do
echo "$item"
done
ARRAY+=("four")
Associative Arrays
declare -A MAP
MAP["key1"]="value1"
MAP["key2"]="value2"
echo "${MAP[key1]}"
[[ -v MAP[key1] ]] && echo "key1 exists"
for key in "${!MAP[@]}"; do
echo "$key: ${MAP[$key]}"
done
Control Flow
Conditionals
[[ "$str" == "value" ]]
[[ "$str" != "value" ]]
[[ -z "$str" ]]
[[ -n "$str" ]]
[[ "$num" -eq 5 ]]
[[ "$num" -ne 5 ]]
[[ "$num" -lt 5 ]]
[[ "$num" -gt 5 ]]
[[ -f "$file" ]]
[[ -d "$dir" ]]
[[ -r "$file" ]]
[[ -w "$file" ]]
[[ -x "$file" ]]
[[ "$a" && "$b" ]]
[[ "$a" || "$b" ]]
[[ ! "$a" ]]
Loops
for i in {1..10}; do
echo "$i"
done
while read -r line; do
echo "$line"
done < "$file"
while read -r line; do
echo "$line"
done < <(command)
for ((i=0; i<10; i++)); do
echo "$i"
done
Input/Output
Reading Input
read -r -p "Enter name: " name
read -r -s -p "Password: " password
read -r -t 5 -p "Quick! " answer
while IFS= read -r line; do
echo "$line"
done < "$file"
Output & Redirection
command > file
command >> file
command 2> file
command &> file
command > file 2>&1
command > /dev/null 2>&1
command | tee file
Text Processing
Common Patterns
find . -name "*.log" -exec grep "ERROR" {} +
while IFS=, read -r col1 col2 col3; do
echo "$col1: $col2"
done < file.csv
jq '.key' file.json
jq -r '.items[]' file.json
awk '{print $1}' file
awk -F: '{print $1}' /etc/passwd
awk 'NR > 1' file
sed 's/old/new/g' file
sed -i 's/old/new/g' file
sed -n '10,20p' file
Best Practices
Do
- Quote all variable expansions:
"$VAR"
- Use
[[ ]] over [ ] for tests
- Use
$(command) over backticks
- Check return values
- Use
readonly for constants
- Use
local in functions
- Provide
--help option
- Use meaningful exit codes
Don't
- Parse
ls output
- Use
eval with untrusted input
- Assume paths don't have spaces
- Ignore shellcheck warnings
- Write one giant script (modularize)
Reference Files
references/one_liners.md - Useful one-liner commands
Integration with Other Skills
- developer-experience - For tooling automation
- debugging - For script debugging
- testing - For script testing patterns