Skip to main content
Bash, despite its ubiquity in system administration and automation, has several common anti-patterns that can lead to bugs, security vulnerabilities, and maintainability issues. Here are the most important anti-patterns to avoid when writing Bash scripts.
Always quote your variables in Bash to prevent word splitting and globbing. Unquoted variables can lead to unexpected behavior, especially when they contain spaces, wildcards, or special characters.
Avoid parsing the output of ls in scripts. It can break when filenames contain spaces, newlines, or other special characters. Use shell globbing, find, or other more robust methods instead.
Always check the exit status of commands, especially those that might fail. Use conditional statements, the set -e option to exit on any error, or combine both approaches for more robust error handling.
Avoid using eval whenever possible, especially with user input. It can lead to code injection vulnerabilities. If you must use it, validate input strictly and consider alternatives like case statements or function dispatching.
Be careful with command arguments that come from user input or external sources. Use -- to indicate the end of options when available, and consider using printf %q to properly quote arguments for commands that don’t support --.
Use $() for command substitution instead of backticks. It’s more readable, especially when nested, and more consistent with other shell constructs.
When reading lines from a file, set IFS= (empty) and use the -r flag with read to prevent backslash interpretation. This preserves leading and trailing whitespace and handles backslashes correctly.
If your script uses Bash-specific features, use #!/bin/bash as the shebang, not #!/bin/sh. On many systems, /bin/sh might be a different shell (like dash) that doesn’t support Bash features.
Use set -u (or set -o nounset) to make your script exit when it tries to use an undefined variable. This helps catch typos and missing variables early.
Use set -e (or set -o errexit) to make your script exit immediately if any command fails. This prevents the script from continuing in an unexpected state after an error.
Use Shellcheck to analyze your Bash scripts for common mistakes and pitfalls. It can catch many of the anti-patterns mentioned here and more.
Use [[ ]] instead of [ ] for conditional tests in Bash. It’s more powerful, safer with empty variables, supports logical operators directly, and provides pattern matching.
Avoid hardcoding absolute paths in your scripts. Use relative paths, determine paths dynamically, or use environment variables to make your scripts more portable and easier to maintain.
Use functions to avoid code duplication and improve maintainability. Functions make your code more modular, easier to understand, and easier to test.
Use printf instead of echo for more consistent behavior across different systems, especially when printing to stderr or when dealing with strings that start with options like -n or -e.
Reserve uppercase variable names for environment variables and constants. Use lowercase for regular variables to avoid conflicts with environment variables and to follow convention.
Use local to declare function-specific variables. This prevents unintended side effects and makes functions more self-contained and reusable.
Use mktemp to create secure temporary files with unique names. Add a trap to clean up temporary files when the script exits, even if it exits due to an error.
Use double brackets [[ ]] with the =~ operator for regular expression matching. Single brackets [ ] only support glob patterns, not regular expressions.
Always include a proper shebang line at the beginning of your script. Using #!/usr/bin/env bash is more portable than #!/bin/bash because it will find the Bash interpreter in the user’s PATH.
Avoid using deprecated syntax like $[...] for arithmetic expansion. Use the modern equivalents like $((...)) instead.
Use parameter expansion for default values, substring operations, and pattern matching. It’s more concise and often more efficient than using conditional statements or external commands.