Skip to content
Back to skills

1238 Shell Patterns 47faf047

ASecurity

Robust patterns for Bash/Zsh scripts.

  • 9 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 11, 2026
businessshellbashgit

Security analysis

A93/100
  • highPerforms destructive filesystem operations

Pro shows the line behind each finding and how to fix it

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 1238-shell-patterns_47faf047 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 1238 Shell Patterns 47faf047?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 1238 Shell Patterns 47faf047
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-1238-shell-patterns-47faf047/badge)](https://www.skillsdirectory.com/skills/tools-only-1238-shell-patterns-47faf047)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
# Shell Script Patterns

Robust patterns for Bash/Zsh scripts.

## Script Header

Always start scripts with:

```bash
#!/usr/bin/env bash
set -euo pipefail

# -e: Exit on error
# -u: Error on undefined variables
# -o pipefail: Pipeline fails if any command fails
```

## Argument Parsing

### Simple positional args

```bash
#!/usr/bin/env bash
set -euo pipefail

if [[ $# -lt 1 ]]; then
    echo "Usage: $0 <filename>" >&2
    exit 1
fi

filename="$1"
```

### Named arguments with getopts

```bash
#!/usr/bin/env bash
set -euo pipefail

usage() {
    echo "Usage: $0 [-v] [-o output] <input>" >&2
    exit 1
}

verbose=false
output=""

while getopts ":vo:" opt; do
    case $opt in
        v) verbose=true ;;
        o) output="$OPTARG" ;;
        \?) echo "Invalid option: -$OPTARG" >&2; usage ;;
        :) echo "Option -$OPTARG requires an argument" >&2; usage ;;
    esac
done
shift $((OPTIND - 1))

[[ $# -lt 1 ]] && usage
input="$1"
```

## Defensive Checks

### Command existence

```bash
command -v git &>/dev/null || {
    echo "Error: git is not installed" >&2
    exit 1
}
```

### File/directory checks

```bash
[[ -f "$file" ]] || { echo "File not found: $file" >&2; exit 1; }
[[ -d "$dir" ]] || { echo "Directory not found: $dir" >&2; exit 1; }
[[ -r "$file" ]] || { echo "File not readable: $file" >&2; exit 1; }
[[ -w "$file" ]] || { echo "File not writable: $file" >&2; exit 1; }
[[ -x "$file" ]] || { echo "File not executable: $file" >&2; exit 1; }
```

### Running as root

```bash
# Require root
[[ $EUID -eq 0 ]] || { echo "Must run as root" >&2; exit 1; }

# Prevent running as root
[[ $EUID -ne 0 ]] || { echo "Do not run as root" >&2; exit 1; }
```

## Variable Defaults

```bash
# Default value if unset
name="${NAME:-default_value}"

# Default value if unset or empty
name="${NAME:-default_value}"

# Error if unset
name="${NAME:?NAME environment variable required}"
```

## String Operations

```bash
# Check if string is empty
[[ -z "$str" ]] && echo "Empty"

# Check if string is non-empty
[[ -n "$str" ]] && echo "Not empty"

# String comparison
[[ "$str" == "value" ]]
[[ "$str" != "value" ]]

# Pattern matching (glob)
[[ "$str" == *.txt ]]

# Regex matching
[[ "$str" =~ ^[0-9]+$ ]]

# Case-insensitive comparison
[[ "${str,,}" == "value" ]]  # Bash 4+
```

## Arrays

```bash
# Define array
files=("one.txt" "two.txt" "three.txt")

# Add element
files+=("four.txt")

# Iterate
for file in "${files[@]}"; do
    echo "$file"
done

# Length
echo "${#files[@]}"

# Index access
echo "${files[0]}"
```

## Loops

### Process lines from file

```bash
while IFS= read -r line; do
    echo "$line"
done < "$file"
```

### Process command output

```bash
while IFS= read -r line; do
    echo "$line"
done < <(some_command)
```

### Process find results safely

```bash
while IFS= read -r -d '' file; do
    echo "$file"
done < <(find . -name "*.txt" -print0)
```

## Temporary Files

```bash
# Create temp file
tmpfile=$(mktemp)
trap 'rm -f "$tmpfile"' EXIT

# Create temp directory
tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT
```

## Error Handling

### Trap on exit

```bash
cleanup() {
    rm -f "$tmpfile"
    echo "Cleanup complete"
}
trap cleanup EXIT
```

### Trap on error

```bash
on_error() {
    echo "Error on line $1" >&2
}
trap 'on_error $LINENO' ERR
```

## Logging

```bash
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
}

error() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: $*" >&2
}

log "Starting script"
error "Something went wrong"
```

## User Interaction

### Confirm before proceeding

```bash
read -rp "Continue? [y/N] " response
[[ "$response" =~ ^[Yy]$ ]] || exit 0
```

### Prompt with default

```bash
read -rp "Enter name [default]: " name
name="${name:-default}"
```

## Path Manipulation

```bash
# Get directory of script
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# Get filename from path
filename="${path##*/}"

# Get directory from path
dirname="${path%/*}"

# Get extension
ext="${filename##*.}"

# Remove extension
basename="${filename%.*}"
```

## Process Management

```bash
# Run in background
long_running_command &
pid=$!

# Wait for completion
wait "$pid"

# Check if process exists
kill -0 "$pid" 2>/dev/null && echo "Running"

# Kill process group
kill -- -"$pid"
```

## Common Pitfalls

- **Always quote variables**: `"$var"` not `$var`
- **Use `[[` not `[`**: `[[` is more powerful and safer
- **Avoid parsing `ls`**: Use glob patterns or `find`
- **Don't use `cat file | grep`**: Use `grep pattern file`
- **Check exit codes**: `if command; then ...` or `command || handle_error`

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.