(grok)Best Practice for Writing Bash Scripts

what is the best practice for writing bash scripts

Writing robust and maintainable Bash scripts requires following best practices to ensure readability, reliability, and portability. Below are key guidelines:

1. Use a Shebang

  • Start your script with #!/bin/bash (or #!/usr/bin/env bash for portability) to specify the interpreter.
  • Example:
    1
    
    #!/usr/bin/env bash

2. Enable Strict Mode

  • Use set commands to catch errors early:
    • set -e: Exit on error.
    • set -u: Exit on unset variables.
    • set -o pipefail: Ensure pipelines fail if any command fails.
  • Example:
    1
    
    set -euo pipefail

3. Add Comments and Documentation

  • Comment your code to explain its purpose and logic, especially for complex sections.
  • Include a header with script purpose, usage, and author info.
  • Example:
    1
    2
    3
    
    # Purpose: Backup user data to a specified directory
    # Usage: ./backup.sh <source> <destination>
    # Author: Jane Doe, 2025

4. Use Meaningful Variable Names

  • Choose descriptive, lowercase variable names (e.g., source_dir instead of sd).
  • Use readonly for constants and local for variables in functions.
  • Example:
    1
    2
    
    readonly BACKUP_DIR="/backup"
    local file_count=0

5. Quote Variables and Strings

  • Always quote variables to prevent issues with unset or empty variables and word splitting.
  • Example:
    1
    
    cp "$source" "$destination"

6. Avoid Unnecessary Subshells

  • Use built-in Bash constructs instead of external commands (e.g., [[ ]] for tests instead of [ ]).
  • Prefer read over echo | grep for parsing.
  • Example:
    1
    2
    3
    
    if [[ -d "$dir" ]]; then
        echo "Directory exists"
    fi

7. Handle Errors Gracefully

  • Check command exit statuses and provide meaningful error messages.
  • Use trap to clean up resources on script exit.
  • Example:
    1
    
    trap 'echo "Error on line $LINENO"; exit 1' ERR

8. Write Modular Code

  • Use functions to organize code and improve reusability.
  • Keep functions small and focused on a single task.
  • Example:
    1
    2
    3
    4
    
    log_message() {
        local message="$1"
        echo "[$(date)] $message" >> "$LOG_FILE"
    }

9. Validate Inputs

  • Check for required arguments and validate input data.
  • Exit with clear error messages if validation fails.
  • Example:
    1
    2
    3
    4
    
    if [[ $# -ne 2 ]]; then
        echo "Usage: $0 <source> <destination>"
        exit 1
    fi

10. Use Consistent Formatting

  • Follow a style guide (e.g., indent with 2 or 4 spaces, avoid tabs).
  • Break long lines for readability (use \ or wrap in functions).
  • Example:
    1
    2
    3
    4
    5
    
    if [[ -n "$variable" ]]; then
        echo "Variable is set"
    else
        echo "Variable is unset"
    fi

11. Test Your Scripts

  • Test scripts in different environments to ensure portability.
  • Use tools like shellcheck to catch common errors and improve quality.
  • Example:
    1
    
    shellcheck myscript.sh

12. Avoid Hardcoding Paths

  • Use variables or relative paths to make scripts portable.
  • Example:
    1
    2
    
    SCRIPT_DIR="$(dirname "$0")"
    source "${SCRIPT_DIR}/config.sh"

13. Log Output

  • Redirect output to log files for debugging and auditing.
  • Use tee to log to both file and stdout.
  • Example:
    1
    
    echo "Starting backup" | tee -a "$LOG_FILE"

14. Use Modern Constructs

  • Prefer [[ ]] over [ ] for conditionals (more robust, supports regex).
  • Use $( ) instead of ` ` for command substitution (better nesting).
  • Example:
    1
    2
    3
    
    if [[ "$name" =~ ^[a-z]+$ ]]; then
        echo "Valid name"
    fi

15. Secure Your Scripts

  • Avoid exposing sensitive data (e.g., passwords) in scripts.
  • Use environment variables or secure vaults for secrets.
  • Set appropriate file permissions (chmod 700 script.sh).
  • Example:
    1
    2
    3
    4
    
    if [[ -z "${DB_PASSWORD:-}" ]]; then
        echo "DB_PASSWORD not set"
        exit 1
    fi

16. Exit Codes

  • Use consistent exit codes (e.g., 0 for success, 1 for general errors).
  • Document custom exit codes in the script header.
  • Example:
    1
    
    exit 0  # Success

17. Profile and Optimize

  • Use time or debugging tools to identify slow sections.
  • Avoid unnecessary loops or external commands.
  • Example:
    1
    
    time ./myscript.sh

Example Script Incorporating Best Practices

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#!/usr/bin/env bash

# Purpose: Copy files from source to destination with logging
# Usage: ./copy.sh <source> <destination>
# Author: Jane Doe, 2025

set -euo pipefail

# Constants
readonly LOG_FILE="/var/log/copy.log"
readonly MAX_FILES=1000

# Functions
log_message() {
    local message="$1"
    echo "[$(date)] $message" | tee -a "$LOG_FILE"
}

validate_inputs() {
    local source="$1"
    local destination="$2"
    if [[ ! -d "$source" ]]; then
        log_message "Error: Source directory does not exist"
        exit 1
    fi
    if [[ ! -d "$destination" ]]; then
        log_message "Creating destination directory: $destination"
        mkdir -p "$destination"
    fi
}

# Main
if [[ $# -ne 2 ]]; then
    echo "Usage: $0 <source> <destination>"
    exit 1
fi

source_dir="$1"
dest_dir="$2"

validate_inputs "$source_dir" "$dest_dir"

log_message "Starting copy from $source_dir to $dest_dir"

file_count=0
while IFS= read -r -d '' file; do
    cp "$file" "$dest_dir/"
    ((file_count++))
    if [[ $file_count -ge $MAX_FILES ]]; then
        log_message "Error: Maximum file limit reached"
        exit 2
    fi
done < <(find "$source_dir" -type f -print0)

log_message "Copy completed. $file_count files copied."
exit 0

Additional Tools and Resources

  • ShellCheck: Static analysis tool for catching syntax and logical errors (shellcheck myscript.sh).
  • Bash Style Guide: Follow Google’s Shell Style Guide or similar for consistency.
  • Testing Frameworks: Use bats for unit testing Bash scripts.

By adhering to these practices, your Bash scripts will be more reliable, easier to maintain, and less prone to errors. Let me know if you need help with a specific script or tool!

william 支付宝支付宝
william 微信微信
0%