G
GuideDevOps
Lesson 14 of 15

Bash Best Practices & Security

Part of the Shell Scripting (Bash) tutorial series.

Writing shell scripts is easy, but writing good shell scripts that are reliable and secure is an art. These best practices will help you avoid common pitfalls and make your scripts "production-grade."

1. Use a Modern Shebang

Instead of #!/bin/bash, use #!/usr/bin/env bash. This makes your script more portable across different Linux distributions and Unix systems.


2. Quoting Variables (Always!)

Unquoted variables can lead to "word splitting" and "globbing" issues.

Bad:

FILE_NAME="my file.txt"
rm $FILE_NAME # This will try to delete "my" and "file.txt" separately!

Good:

FILE_NAME="my file.txt"
rm "$FILE_NAME" # Always double-quote variable expansions.

3. Use [[ ]] instead of [ ]

[[ ]] is a Bash-specific (and Zsh) upgrade to the POSIX [ ] (also known as test). It's more powerful and less likely to cause errors.

Feature[ ][[ ]]
Logic-a, -o&&, `
Pattern MatchingNoYes (Regex support)
Word SplittingYes (Problematic)No (Safe)

Example:

if [[ $NAME == "DevOps" && $STATUS == "Ready" ]]; then
    echo "Go!"
fi

4. Descriptive Variable Names

Avoid single-letter variables like i, x, or y except for very short loops. Use UPPERCASE for global constants and lowercase for local variables.

# Good
readonly LOG_FILE="/var/log/app.log"
local_count=0

5. Security: Handling Secrets

NEVER hardcode API keys or passwords in scripts.

Avoid:

export GITHUB_TOKEN="ghp_1234567890abcdef"

Best Practice:

  • Use environment variables (from CI/CD tools like GitHub Actions secrets).
  • Use a secret manager (like AWS Secrets Manager, HashiCorp Vault).
  • Prompt the user (using read -s).

6. Make Scripts Idempotent

An idempotent script can be run multiple times and will only make changes when necessary, without causing errors.

Bad:

mkdir my_dir # Fails if directory exists

Good:

mkdir -p my_dir # Continues silently if directory exists

7. Temporary Files

Always use mktemp for creating temporary files instead of hardcoded names like /tmp/temp.txt. This prevents security risks and collisions.

# Create a secure temporary file
tmpfile=$(mktemp)
# Register a cleanup function to delete it on exit
trap 'rm -f "$tmpfile"' EXIT
 
echo "processing data..." > "$tmpfile"

Summary: The Golden Rules

  1. Always double-quote your variables.
  2. Use set -euo pipefail at the top.
  3. Use ShellCheck to lint your code.
  4. Keep functions small and modular.
  5. Use local for variables inside functions.