shell-engineering

Comprehensive guidelines for writing production-quality shell scripts based on Google's Shell Style Guide.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "shell-engineering" with this command: npx skills add gonzaloserrano/dotfiles/gonzaloserrano-dotfiles-shell-engineering

Shell Engineering

Comprehensive guidelines for writing production-quality shell scripts based on Google's Shell Style Guide.

When to Use Shell

  • Small utilities and simple wrapper scripts

  • Scripts calling other tools with straightforward logic

  • Rewrite in a structured language (Go, Python) when exceeding ~100 lines or using complex control flow

Shell Choice

  • Bash is the only permitted shell for executables

  • Start scripts with #!/bin/bash with minimal flags

  • Libraries must have .sh extension and not be executable

  • SUID/SGID are forbidden on shell scripts

File Structure

#!/bin/bash

Brief description of the script's purpose.

set -euo pipefail

Constants and environment variables (UPPERCASE)

readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" readonly LOG_FILE="/tmp/script.log"

Source libraries

source "${SCRIPT_DIR}/lib/utils.sh"

Function definitions (lowercase_with_underscores)

my_function() { local arg1="$1"

...

}

Main function

main() {

Script logic here

}

main "$@"

Formatting Rules

Indentation and Length

  • 2 spaces for indentation (no tabs)

  • 80 characters maximum line length

  • Split long pipelines with pipe at line start:

command1
| command2
| command3

Control Structures

  • ; then and ; do on same line as if /while /for :

if [[ -n "${var}" ]]; then

...

fi

for file in "${files[@]}"; do

...

done

Quoting

  • Always quote strings with variables, command substitutions, or spaces

  • Use "${var}" format with braces for clarity

  • Use "$@" not $* for argument lists

  • Use arrays for lists with spaces in elements

Naming Conventions

Type Convention Example

Functions lowercase_underscores

process_file()

Variables lowercase_underscores

file_count

Constants UPPERCASE_UNDERSCORES

readonly MAX_RETRIES=3

Environment vars UPPERCASE

export PATH

Source files lowercase_underscores.sh

string_utils.sh

Preferred Syntax

Use These

Command substitution

result=$(command)

Test conditions

if [[ -n "${var}" ]]; then

Arithmetic

if (( count > 10 )); then total=$(( a + b ))

Local variables in functions

my_func() { local name="$1" }

Arrays for lists

files=("file1.txt" "file2.txt" "file with spaces.txt") for f in "${files[@]}"; do

Avoid These

Backticks (use $() instead)

result=command

Single brackets (use [[ ]] instead)

if [ -n "$var" ]; then

let, expr, $[ ] (use $(( )) instead)

let count=count+1

eval (security risk)

eval "$cmd"

Piping to while (loses variable scope)

cat file | while read line; do

alias in scripts (use functions)

alias ll='ls -la'

Unquoted wildcards

for f in ; do # Use ./ instead

Error Handling

STDERR for Errors

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

if ! process_file "${file}"; then err "Failed to process ${file}" exit 1 fi

Check Return Values

Direct if check

if ! mv "${file}" "${dest}"; then err "Failed to move file" fi

Pipeline status

tar -cf - . | gzip > archive.tar.gz if (( PIPESTATUS[0] != 0 || PIPESTATUS[1] != 0 )); then err "Archive creation failed" fi

Comments and Documentation

File Header (Required)

#!/bin/bash

Script description explaining purpose and usage.

Usage: script.sh [options] <input_file>

Function Documentation

#######################################

Process a data file and output results.

Globals:

OUTPUT_DIR

Arguments:

$1 - Input file path

$2 - Output format (csv|json)

Outputs:

Writes processed data to OUTPUT_DIR

Returns:

0 on success, non-zero on error

####################################### process_data() { local input_file="$1" local format="${2:-csv}"

...

}

TODO Comments

TODO(username): Handle edge case for empty input

Testing and Validation

  • Use ShellCheck to identify bugs

  • Test string emptiness explicitly:

Good

if [[ -z "${var}" ]]; then # empty if [[ -n "${var}" ]]; then # non-empty

Avoid

if [[ "${var}" ]]; then

Built-in Preference

Prefer bash builtins over external commands:

Good: parameter expansion

filename="${path##/}" extension="${filename##.}" basename="${filename%.*}"

Avoid: external commands

filename=$(basename "$path") extension=$(echo "$filename" | sed 's/.*.//')

Quick Reference

Do Don't

$(command)

command

[[ condition ]]

[ condition ]

(( arithmetic ))

let , expr

"${var}"

$var

"$@"

$*

local var

global variables in functions

./* wildcards * wildcards

functions aliases

arrays space-separated strings

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

go-engineering

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

typescript-engineering

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

python-engineering

No summary provided by upstream source.

Repository SourceNeeds Review