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 Error Handling Set Options Trap for Cleanup Error Checking Patterns Variables & Substitution Variable Expansion Arrays Associative Arrays Control Flow Conditionals Loops Input/Output Reading Input Outpu…

\\n\\t' # Safer word splitting\n\n# Constants\nreadonly SCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nreadonly SCRIPT_NAME=\"$(basename \"${BASH_SOURCE[0]}\")\"\n\n# Default values\nVERBOSE=false\nDRY_RUN=false\n\n# Functions\nusage() {\n cat \u003c\u003cEOF\nUsage: $SCRIPT_NAME [options] \u003cargument>\n\nOptions:\n -h, --help Show this help message\n -v, --verbose Enable verbose output\n -n, --dry-run Show what would be done\nEOF\n}\n\nlog() {\n echo \"[$(date +'%Y-%m-%d %H:%M:%S')] $*\" >&2\n}\n\nerror() {\n log \"ERROR: $*\"\n exit 1\n}\n\n# Main logic\nmain() {\n # Parse arguments\n while [[ $# -gt 0 ]]; do\n case \"$1\" in\n -h|--help)\n usage\n exit 0\n ;;\n -v|--verbose)\n VERBOSE=true\n shift\n ;;\n -n|--dry-run)\n DRY_RUN=true\n shift\n ;;\n *)\n break\n ;;\n esac\n done\n\n # Your logic here\n}\n\nmain \"$@\"\n```\n\n## Error Handling\n\n### Set Options\n\n```bash\nset -e # Exit on any error\nset -u # Error on undefined variables\nset -o pipefail # Pipe failure is script failure\nset -x # Debug: print each command (use sparingly)\n```\n\n### Trap for Cleanup\n\n```bash\ncleanup() {\n rm -f \"$TEMP_FILE\"\n log \"Cleanup complete\"\n}\ntrap cleanup EXIT\n\n# Also handle specific signals\ntrap 'error \"Script interrupted\"' INT TERM\n```\n\n### Error Checking Patterns\n\n```bash\n# Check command exists\ncommand -v jq >/dev/null 2>&1 || error \"jq is required but not installed\"\n\n# Check file exists\n[[ -f \"$FILE\" ]] || error \"File not found: $FILE\"\n\n# Check directory exists\n[[ -d \"$DIR\" ]] || mkdir -p \"$DIR\"\n\n# Check variable is set\n[[ -n \"${VAR:-}\" ]] || error \"VAR is not set\"\n\n# Check exit status explicitly\nif ! some_command; then\n error \"some_command failed\"\nfi\n```\n\n## Variables & Substitution\n\n### Variable Expansion\n\n```bash\n# Default values\n${VAR:-default} # Use default if VAR is unset or empty\n${VAR:=default} # Set VAR to default if unset or empty\n${VAR:+value} # Use value if VAR is set\n${VAR:?error msg} # Error if VAR is unset or empty\n\n# String manipulation\n${VAR#pattern} # Remove shortest prefix match\n${VAR##pattern} # Remove longest prefix match\n${VAR%pattern} # Remove shortest suffix match\n${VAR%%pattern} # Remove longest suffix match\n${VAR/old/new} # Replace first occurrence\n${VAR//old/new} # Replace all occurrences\n${#VAR} # Length of VAR\n```\n\n### Arrays\n\n```bash\n# Declare array\ndeclare -a ARRAY=(\"one\" \"two\" \"three\")\n\n# Access elements\necho \"${ARRAY[0]}\" # First element\necho \"${ARRAY[@]}\" # All elements\necho \"${#ARRAY[@]}\" # Number of elements\necho \"${!ARRAY[@]}\" # All indices\n\n# Iterate\nfor item in \"${ARRAY[@]}\"; do\n echo \"$item\"\ndone\n\n# Append\nARRAY+=(\"four\")\n```\n\n### Associative Arrays\n\n```bash\ndeclare -A MAP\nMAP[\"key1\"]=\"value1\"\nMAP[\"key2\"]=\"value2\"\n\n# Access\necho \"${MAP[key1]}\"\n\n# Check key exists\n[[ -v MAP[key1] ]] && echo \"key1 exists\"\n\n# Iterate\nfor key in \"${!MAP[@]}\"; do\n echo \"$key: ${MAP[$key]}\"\ndone\n```\n\n## Control Flow\n\n### Conditionals\n\n```bash\n# String comparison\n[[ \"$str\" == \"value\" ]]\n[[ \"$str\" != \"value\" ]]\n[[ -z \"$str\" ]] # Empty\n[[ -n \"$str\" ]] # Not empty\n\n# Numeric comparison\n[[ \"$num\" -eq 5 ]] # Equal\n[[ \"$num\" -ne 5 ]] # Not equal\n[[ \"$num\" -lt 5 ]] # Less than\n[[ \"$num\" -gt 5 ]] # Greater than\n\n# File tests\n[[ -f \"$file\" ]] # File exists\n[[ -d \"$dir\" ]] # Directory exists\n[[ -r \"$file\" ]] # Readable\n[[ -w \"$file\" ]] # Writable\n[[ -x \"$file\" ]] # Executable\n\n# Logical operators\n[[ \"$a\" && \"$b\" ]] # AND\n[[ \"$a\" || \"$b\" ]] # OR\n[[ ! \"$a\" ]] # NOT\n```\n\n### Loops\n\n```bash\n# For loop\nfor i in {1..10}; do\n echo \"$i\"\ndone\n\n# While loop\nwhile read -r line; do\n echo \"$line\"\ndone \u003c \"$file\"\n\n# Process substitution\nwhile read -r line; do\n echo \"$line\"\ndone \u003c \u003c(command)\n\n# C-style for\nfor ((i=0; i\u003c10; i++)); do\n echo \"$i\"\ndone\n```\n\n## Input/Output\n\n### Reading Input\n\n```bash\n# Read from user\nread -r -p \"Enter name: \" name\n\n# Read password (hidden)\nread -r -s -p \"Password: \" password\n\n# Read with timeout\nread -r -t 5 -p \"Quick! \" answer\n\n# Read file line by line\nwhile IFS= read -r line; do\n echo \"$line\"\ndone \u003c \"$file\"\n```\n\n### Output & Redirection\n\n```bash\n# Redirect stdout\ncommand > file # Overwrite\ncommand >> file # Append\n\n# Redirect stderr\ncommand 2> file\n\n# Redirect both\ncommand &> file\ncommand > file 2>&1\n\n# Discard output\ncommand > /dev/null 2>&1\n\n# Tee (output and save)\ncommand | tee file\n```\n\n## Text Processing\n\n### Common Patterns\n\n```bash\n# Find and process files\nfind . -name \"*.log\" -exec grep \"ERROR\" {} +\n\n# Process CSV\nwhile IFS=, read -r col1 col2 col3; do\n echo \"$col1: $col2\"\ndone \u003c file.csv\n\n# JSON processing (with jq)\njq '.key' file.json\njq -r '.items[]' file.json\n\n# AWK one-liners\nawk '{print $1}' file # First column\nawk -F: '{print $1}' /etc/passwd # Custom delimiter\nawk 'NR > 1' file # Skip header\n\n# SED one-liners\nsed 's/old/new/g' file # Replace all\nsed -i 's/old/new/g' file # In-place edit\nsed -n '10,20p' file # Print lines 10-20\n```\n\n## Best Practices\n\n### Do\n\n- Quote all variable expansions: `\"$VAR\"`\n- Use `[[ ]]` over `[ ]` for tests\n- Use `$(command)` over backticks\n- Check return values\n- Use `readonly` for constants\n- Use `local` in functions\n- Provide `--help` option\n- Use meaningful exit codes\n\n### Don't\n\n- Parse `ls` output\n- Use `eval` with untrusted input\n- Assume paths don't have spaces\n- Ignore shellcheck warnings\n- Write one giant script (modularize)\n\n## Reference Files\n\n- **`references/one_liners.md`** - Useful one-liner commands\n\n## Integration with Other Skills\n\n- **developer-experience** - For tooling automation\n- **debugging** - For script debugging\n- **testing** - For script testing patterns\n---","attachment_filenames":["skill-report.json"],"attachments":[{"filename":"skill-report.json","content":"{\n \"schema_version\": \"2.0\",\n \"meta\": {\n \"generated_at\": \"2026-01-16T14:06:30.050Z\",\n \"slug\": \"89jobrien-shell-scripting\",\n \"source_url\": \"https://github.com/89jobrien/steve/tree/main/steve/skills/shell-scripting\",\n \"source_ref\": \"main\",\n \"model\": \"claude\",\n \"analysis_version\": \"3.0.0\",\n \"source_type\": \"community\",\n \"content_hash\": \"1c235d8c8c358a099fc9c38ae08a5ee187e7e89cbf7056a5bf1dfb4f16f7ebb9\",\n \"tree_hash\": \"ff3204c7f0e6150f528d622f009391173e5f95fbf02b101df252df822fc36d2f\"\n },\n \"skill\": {\n \"name\": \"shell-scripting\",\n \"description\": \"Shell scripting best practices and patterns. Use when writing bash/zsh scripts, automating tasks, creating CLI tools, or debugging shell commands.\",\n \"summary\": \"Shell scripting best practices and patterns. Use when writing bash/zsh scripts, automating tasks, cr...\",\n \"icon\": \"🐚\",\n \"version\": \"1.0.1\",\n \"author\": \"Joseph OBrien\",\n \"license\": \"MIT\",\n \"category\": \"coding\",\n \"tags\": [\n \"shell\",\n \"bash\",\n \"automation\",\n \"scripting\",\n \"cli\"\n ],\n \"supported_tools\": [\n \"claude\",\n \"codex\",\n \"claude-code\"\n ],\n \"risk_factors\": [\n \"network\",\n \"external_commands\",\n \"filesystem\"\n ]\n },\n \"security_audit\": {\n \"risk_level\": \"safe\",\n \"is_blocked\": false,\n \"safe_to_publish\": true,\n \"summary\": \"Pure documentation skill containing markdown guidance only. The static scanner flagged 62 potential issues, but ALL are false positives because this skill contains no executable code - only instructional shell scripting patterns in markdown code blocks. The skill-report.json security_audit already correctly assessed this as 'safe' with no risk factors present.\",\n \"risk_factor_evidence\": [\n {\n \"factor\": \"network\",\n \"evidence\": [\n {\n \"file\": \"skill-report.json\",\n \"line_start\": 6,\n \"line_end\": 6\n }\n ]\n },\n {\n \"factor\": \"external_commands\",\n \"evidence\": [\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 31,\n \"line_end\": 96\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 96,\n \"line_end\": 102\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 102,\n \"line_end\": 107\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 107,\n \"line_end\": 111\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 111,\n \"line_end\": 120\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 120,\n \"line_end\": 124\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 124,\n \"line_end\": 141\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 141,\n \"line_end\": 147\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 147,\n \"line_end\": 162\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 162,\n \"line_end\": 166\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 166,\n \"line_end\": 183\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 183,\n \"line_end\": 187\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 187,\n \"line_end\": 202\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 202,\n \"line_end\": 208\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 208,\n \"line_end\": 232\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 232,\n \"line_end\": 236\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 236,\n \"line_end\": 256\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 256,\n \"line_end\": 262\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 262,\n \"line_end\": 276\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 276,\n \"line_end\": 280\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 280,\n \"line_end\": 297\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 297,\n \"line_end\": 303\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 303,\n \"line_end\": 325\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 325,\n \"line_end\": 331\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 331,\n \"line_end\": 332\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 332,\n \"line_end\": 332\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 332,\n \"line_end\": 333\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 333,\n \"line_end\": 335\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 335,\n \"line_end\": 336\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 336,\n \"line_end\": 337\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 337,\n \"line_end\": 342\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 342,\n \"line_end\": 343\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 343,\n \"line_end\": 350\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 41,\n \"line_end\": 41\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 42,\n \"line_end\": 42\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 61,\n \"line_end\": 61\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 333,\n \"line_end\": 333\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 31,\n \"line_end\": 96\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 333,\n \"line_end\": 333\n }\n ]\n },\n {\n \"factor\": \"filesystem\",\n \"evidence\": [\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 126,\n \"line_end\": 126\n },\n {\n \"file\": \"SKILL.md\",\n \"line_start\": 293,\n \"line_end\": 293\n }\n ]\n }\n ],\n \"critical_findings\": [],\n \"high_findings\": [],\n \"medium_findings\": [],\n \"low_findings\": [],\n \"dangerous_patterns\": [],\n \"files_scanned\": 2,\n \"total_lines\": 535,\n \"audit_model\": \"claude\",\n \"audited_at\": \"2026-01-16T14:06:30.050Z\"\n },\n \"content\": {\n \"user_title\": \"Write reliable shell scripts with best practices\",\n \"value_statement\": \"Shell scripts often fail silently or behave unpredictably due to missing error handling. This skill provides battle-tested patterns for robust bash and zsh scripting including proper error handling, safe variable expansion, and modular code structure.\",\n \"seo_keywords\": [\n \"shell scripting\",\n \"bash scripting\",\n \"bash best practices\",\n \"zsh automation\",\n \"shell scripts\",\n \"cli tools\",\n \"bash error handling\",\n \"script automation\",\n \"Claude Code\",\n \"Claude\",\n \"Codex\"\n ],\n \"actual_capabilities\": [\n \"Apply safe script structure with set -euo pipefail\",\n \"Implement proper error handling with trap and exit codes\",\n \"Use safe variable expansion and default values\",\n \"Process text with find, awk, sed, and jq patterns\",\n \"Create modular scripts with functions and constants\",\n \"Build CLI tools with argument parsing and help output\"\n ],\n \"limitations\": [\n \"Does not execute scripts on your system\",\n \"Does not provide ready-to-run script templates\",\n \"Does not install or configure shell environments\"\n ],\n \"use_cases\": [\n {\n \"target_user\": \"System administrators\",\n \"title\": \"Automate system maintenance\",\n \"description\": \"Create reliable maintenance scripts with proper cleanup and error handling for production systems.\"\n },\n {\n \"target_user\": \"Developers\",\n \"title\": \"Build CLI automation tools\",\n \"description\": \"Develop robust command-line tools with argument parsing, usage help, and meaningful error messages.\"\n },\n {\n \"target_user\": \"DevOps engineers\",\n \"title\": \"Write safe build scripts\",\n \"description\": \"Create build and deployment scripts that fail fast and provide clear feedback on errors.\"\n }\n ],\n \"prompt_templates\": [\n {\n \"title\": \"Basic script structure\",\n \"scenario\": \"Create a new bash script\",\n \"prompt\": \"Write a bash script template with proper error handling using set -euo pipefail, argument parsing for verbose and dry-run options, and a main function structure.\"\n },\n {\n \"title\": \"Error handling patterns\",\n \"scenario\": \"Add error handling to a script\",\n \"prompt\": \"Add bash error handling to my script using trap for cleanup on EXIT, INT, and TERM signals. Include command existence checks and file validation.\"\n },\n {\n \"title\": \"Text processing pipeline\",\n \"scenario\": \"Process log files\",\n \"prompt\": \"Create a bash script that uses find, awk, and sed to process log files. Find all .log files, extract ERROR lines, and create a summary report.\"\n },\n {\n \"title\": \"CLI tool development\",\n \"scenario\": \"Build a CLI utility\",\n \"prompt\": \"Develop a bash CLI tool with argument parsing using getopts, help output with usage information, subcommands, and proper exit codes for different error conditions.\"\n }\n ],\n \"output_examples\": [\n {\n \"input\": \"Write a bash script that processes CSV files safely\",\n \"output\": [\n \"Use IFS=, to properly split CSV columns\",\n \"Check file exists before reading with [[ -f \\\"$file\\\" ]]\",\n \"Handle empty lines and malformed data gracefully\",\n \"Use set -euo pipefail for robust error handling\",\n \"Quote all variable expansions: \\\"$VAR\\\"\"\n ]\n },\n {\n \"input\": \"How do I handle errors in my shell scripts\",\n \"output\": [\n \"Use set -euo pipefail at script start\",\n \"Check command exit codes explicitly with if ! command\",\n \"Use trap for cleanup on EXIT, INT, and TERM\",\n \"Validate inputs before processing with [[ -n \\\"$VAR\\\" ]]\",\n \"Provide meaningful error messages with exit codes\"\n ]\n },\n {\n \"input\": \"Create a script that finds large files and reports them\",\n \"output\": [\n \"Use find with -size option for file size filtering\",\n \"Process results with while read loop for safety\",\n \"Generate timestamped reports with date formatting\",\n \"Handle spaces in filenames with proper quoting\",\n \"Add verbose mode for debugging output\"\n ]\n }\n ],\n \"best_practices\": [\n \"Always use set -euo pipefail and quote all variable expansions to prevent silent failures\",\n \"Implement cleanup handlers with trap for temporary files and resources\",\n \"Validate all inputs and check command exit codes explicitly\"\n ],\n \"anti_patterns\": [\n \"Avoid parsing ls output - use globs and find instead\",\n \"Never use eval with untrusted or user-supplied input\",\n \"Do not assume paths are safe - always quote and validate\"\n ],\n \"faq\": [\n {\n \"question\": \"What shells does this skill support?\",\n \"answer\": \"This skill focuses on bash and zsh, which are the most common shells for scripting on Linux and macOS systems.\"\n },\n {\n \"question\": \"What are the key error handling options?\",\n \"answer\": \"set -e (exit on error), set -u (error on undefined vars), and set -o pipefail (catch pipe failures) are the core options.\"\n },\n {\n \"question\": \"How does this skill integrate with Claude Code?\",\n \"answer\": \"Request shell scripting guidance using natural language. The skill provides patterns you can apply directly in your scripts.\"\n },\n {\n \"question\": \"Is this skill safe to use?\",\n \"answer\": \"Yes. This skill only provides guidance and patterns. It does not execute code or modify files on your system.\"\n },\n {\n \"question\": \"Why does my script fail silently?\",\n \"answer\": \"Without set -euo pipefail, bash continues on errors. Add these options and check exit codes explicitly for reliable scripts.\"\n },\n {\n \"question\": \"How is this different from AI code generators?\",\n \"answer\": \"This skill teaches patterns and best practices. Use it to understand shell scripting or request specific patterns rather than generating complete scripts.\"\n }\n ]\n },\n \"file_structure\": [\n {\n \"name\": \"SKILL.md\",\n \"type\": \"file\",\n \"path\": \"SKILL.md\",\n \"lines\": 357\n }\n ]\n}\n","content_type":"application/json; charset=utf-8","language":"json","size":13520,"content_sha256":"3d4ca6064d1ca9776ee78d632f4d0b5281bf6657746aebf87360424e63cb857f"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Shell Scripting","type":"text"}]},{"type":"paragraph","content":[{"text":"Comprehensive shell scripting skill covering bash/zsh patterns, automation, error handling, and CLI tool development.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"When to Use This Skill","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Writing automation scripts","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Creating CLI tools","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"System administration tasks","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Build and deployment scripts","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Log processing and analysis","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"File manipulation and batch operations","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Cron jobs and scheduled tasks","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Script Structure","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Template","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"#!/usr/bin/env bash\n# Script: name.sh\n# Description: What this script does\n# Usage: ./name.sh [options] \u003cargs>\n\nset -euo pipefail # Exit on error, undefined vars, pipe failures\nIFS=

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 Error Handling Set Options Trap for Cleanup Error Checking Patterns Variables & Substitution Variable Expansion Arrays Associative Arrays Control Flow Conditionals Loops Input/Output Reading Input Outpu…

\\n\\t' # Safer word splitting\n\n# Constants\nreadonly SCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nreadonly SCRIPT_NAME=\"$(basename \"${BASH_SOURCE[0]}\")\"\n\n# Default values\nVERBOSE=false\nDRY_RUN=false\n\n# Functions\nusage() {\n cat \u003c\u003cEOF\nUsage: $SCRIPT_NAME [options] \u003cargument>\n\nOptions:\n -h, --help Show this help message\n -v, --verbose Enable verbose output\n -n, --dry-run Show what would be done\nEOF\n}\n\nlog() {\n echo \"[$(date +'%Y-%m-%d %H:%M:%S')] $*\" >&2\n}\n\nerror() {\n log \"ERROR: $*\"\n exit 1\n}\n\n# Main logic\nmain() {\n # Parse arguments\n while [[ $# -gt 0 ]]; do\n case \"$1\" in\n -h|--help)\n usage\n exit 0\n ;;\n -v|--verbose)\n VERBOSE=true\n shift\n ;;\n -n|--dry-run)\n DRY_RUN=true\n shift\n ;;\n *)\n break\n ;;\n esac\n done\n\n # Your logic here\n}\n\nmain \"$@\"","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Error Handling","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Set Options","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"set -e # Exit on any error\nset -u # Error on undefined variables\nset -o pipefail # Pipe failure is script failure\nset -x # Debug: print each command (use sparingly)","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Trap for Cleanup","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"cleanup() {\n rm -f \"$TEMP_FILE\"\n log \"Cleanup complete\"\n}\ntrap cleanup EXIT\n\n# Also handle specific signals\ntrap 'error \"Script interrupted\"' INT TERM","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Error Checking Patterns","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Check command exists\ncommand -v jq >/dev/null 2>&1 || error \"jq is required but not installed\"\n\n# Check file exists\n[[ -f \"$FILE\" ]] || error \"File not found: $FILE\"\n\n# Check directory exists\n[[ -d \"$DIR\" ]] || mkdir -p \"$DIR\"\n\n# Check variable is set\n[[ -n \"${VAR:-}\" ]] || error \"VAR is not set\"\n\n# Check exit status explicitly\nif ! some_command; then\n error \"some_command failed\"\nfi","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Variables & Substitution","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Variable Expansion","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Default values\n${VAR:-default} # Use default if VAR is unset or empty\n${VAR:=default} # Set VAR to default if unset or empty\n${VAR:+value} # Use value if VAR is set\n${VAR:?error msg} # Error if VAR is unset or empty\n\n# String manipulation\n${VAR#pattern} # Remove shortest prefix match\n${VAR##pattern} # Remove longest prefix match\n${VAR%pattern} # Remove shortest suffix match\n${VAR%%pattern} # Remove longest suffix match\n${VAR/old/new} # Replace first occurrence\n${VAR//old/new} # Replace all occurrences\n${#VAR} # Length of VAR","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Arrays","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Declare array\ndeclare -a ARRAY=(\"one\" \"two\" \"three\")\n\n# Access elements\necho \"${ARRAY[0]}\" # First element\necho \"${ARRAY[@]}\" # All elements\necho \"${#ARRAY[@]}\" # Number of elements\necho \"${!ARRAY[@]}\" # All indices\n\n# Iterate\nfor item in \"${ARRAY[@]}\"; do\n echo \"$item\"\ndone\n\n# Append\nARRAY+=(\"four\")","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Associative Arrays","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"declare -A MAP\nMAP[\"key1\"]=\"value1\"\nMAP[\"key2\"]=\"value2\"\n\n# Access\necho \"${MAP[key1]}\"\n\n# Check key exists\n[[ -v MAP[key1] ]] && echo \"key1 exists\"\n\n# Iterate\nfor key in \"${!MAP[@]}\"; do\n echo \"$key: ${MAP[$key]}\"\ndone","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Control Flow","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Conditionals","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# String comparison\n[[ \"$str\" == \"value\" ]]\n[[ \"$str\" != \"value\" ]]\n[[ -z \"$str\" ]] # Empty\n[[ -n \"$str\" ]] # Not empty\n\n# Numeric comparison\n[[ \"$num\" -eq 5 ]] # Equal\n[[ \"$num\" -ne 5 ]] # Not equal\n[[ \"$num\" -lt 5 ]] # Less than\n[[ \"$num\" -gt 5 ]] # Greater than\n\n# File tests\n[[ -f \"$file\" ]] # File exists\n[[ -d \"$dir\" ]] # Directory exists\n[[ -r \"$file\" ]] # Readable\n[[ -w \"$file\" ]] # Writable\n[[ -x \"$file\" ]] # Executable\n\n# Logical operators\n[[ \"$a\" && \"$b\" ]] # AND\n[[ \"$a\" || \"$b\" ]] # OR\n[[ ! \"$a\" ]] # NOT","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Loops","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# For loop\nfor i in {1..10}; do\n echo \"$i\"\ndone\n\n# While loop\nwhile read -r line; do\n echo \"$line\"\ndone \u003c \"$file\"\n\n# Process substitution\nwhile read -r line; do\n echo \"$line\"\ndone \u003c \u003c(command)\n\n# C-style for\nfor ((i=0; i\u003c10; i++)); do\n echo \"$i\"\ndone","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Input/Output","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Reading Input","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Read from user\nread -r -p \"Enter name: \" name\n\n# Read password (hidden)\nread -r -s -p \"Password: \" password\n\n# Read with timeout\nread -r -t 5 -p \"Quick! \" answer\n\n# Read file line by line\nwhile IFS= read -r line; do\n echo \"$line\"\ndone \u003c \"$file\"","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Output & Redirection","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Redirect stdout\ncommand > file # Overwrite\ncommand >> file # Append\n\n# Redirect stderr\ncommand 2> file\n\n# Redirect both\ncommand &> file\ncommand > file 2>&1\n\n# Discard output\ncommand > /dev/null 2>&1\n\n# Tee (output and save)\ncommand | tee file","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Text Processing","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Common Patterns","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Find and process files\nfind . -name \"*.log\" -exec grep \"ERROR\" {} +\n\n# Process CSV\nwhile IFS=, read -r col1 col2 col3; do\n echo \"$col1: $col2\"\ndone \u003c file.csv\n\n# JSON processing (with jq)\njq '.key' file.json\njq -r '.items[]' file.json\n\n# AWK one-liners\nawk '{print $1}' file # First column\nawk -F: '{print $1}' /etc/passwd # Custom delimiter\nawk 'NR > 1' file # Skip header\n\n# SED one-liners\nsed 's/old/new/g' file # Replace all\nsed -i 's/old/new/g' file # In-place edit\nsed -n '10,20p' file # Print lines 10-20","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Best Practices","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Do","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Quote all variable expansions: ","type":"text"},{"text":"\"$VAR\"","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"[[ ]]","type":"text","marks":[{"type":"code_inline"}]},{"text":" over ","type":"text"},{"text":"[ ]","type":"text","marks":[{"type":"code_inline"}]},{"text":" for tests","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"$(command)","type":"text","marks":[{"type":"code_inline"}]},{"text":" over backticks","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Check return values","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"readonly","type":"text","marks":[{"type":"code_inline"}]},{"text":" for constants","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"local","type":"text","marks":[{"type":"code_inline"}]},{"text":" in functions","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Provide ","type":"text"},{"text":"--help","type":"text","marks":[{"type":"code_inline"}]},{"text":" option","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use meaningful exit codes","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Don't","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Parse ","type":"text"},{"text":"ls","type":"text","marks":[{"type":"code_inline"}]},{"text":" output","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"eval","type":"text","marks":[{"type":"code_inline"}]},{"text":" with untrusted input","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Assume paths don't have spaces","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Ignore shellcheck warnings","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Write one giant script (modularize)","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Reference Files","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"references/one_liners.md","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" - Useful one-liner commands","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Integration with Other Skills","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"developer-experience","type":"text","marks":[{"type":"strong"}]},{"text":" - For tooling automation","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"debugging","type":"text","marks":[{"type":"strong"}]},{"text":" - For script debugging","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"testing","type":"text","marks":[{"type":"strong"}]},{"text":" - For script testing patterns","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}}]},"metadata":{"tag":"skill","date":"2026-06-05","name":"shell-scripting","type":"skill","author":"@skillopedia","source":{"stars":336,"repo_name":"marketplace","origin_url":"https://github.com/aiskillstore/marketplace/blob/HEAD/skills/89jobrien/shell-scripting/SKILL.md","repo_owner":"aiskillstore","body_sha256":"c9b026fd68fb773d6d3274e9d5a7d29ecce2647782212b1e1a1fafcb0a4e3e95","cluster_key":"8dd77f69670ca3e5432fb2418c0f119fe1b3cbb43f80e303680f83d6b0d9bb69","clean_bundle":{"format":"clean-skill-bundle-v1","source":"aiskillstore/marketplace/skills/89jobrien/shell-scripting/SKILL.md","attachments":[{"id":"7f132b09-5849-563b-a6f9-04428456059d","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/7f132b09-5849-563b-a6f9-04428456059d/attachment.json","path":"skill-report.json","size":13520,"sha256":"3d4ca6064d1ca9776ee78d632f4d0b5281bf6657746aebf87360424e63cb857f","contentType":"application/json; charset=utf-8"}],"bundle_sha256":"45a36a6fad9968342b2ee0e0a80ecb48aab4193d32c733a4983e4fae23fe8423","attachment_count":1,"text_attachments":1,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":0,"excluded_attachments":[]},"cluster_size":2,"skill_md_path":"skills/89jobrien/shell-scripting/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"productivity-workflow","category_label":"Productivity"},"exact_dupes_collapsed_into_this":1},"status":"unpublished","updated":"2025-12-23","version":"v1","category":"productivity-workflow","import_tag":"clean-skills-v1","description":"Shell scripting best practices and patterns. Use when writing bash/zsh scripts, automating tasks, creating CLI tools, or debugging shell commands."}},"renderedAt":1782979288690}

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 Error Handling Set Options Trap for Cleanup Error Checking Patterns Variables & Substitution Variable Expansion Arrays Associative Arrays Control Flow Conditionals Loops Input/Output Reading Input Outpu…