CtrlK
BlogDocsLog inGet started
Tessl Logo

pantheon-ai/bash-script-toolkit

Complete bash-script toolkit with generation and validation capabilities

97

Quality

97%

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Risky

Do not use without reviewing

Overview
Quality
Evals
Security
Files

common-mistakes.mdvalidator/references/

Common Shell Scripting Mistakes

This guide covers frequent mistakes made in bash and shell scripts, their consequences, and how to fix them.

1. Unquoted Variables

Problem

# Wrong
file=/path/with spaces/file.txt
cat $file  # Breaks into multiple arguments

Consequence

Word splitting and glob expansion cause unexpected behavior.

Solution

# Right
file="/path/with spaces/file.txt"
cat "$file"

Rule

Always quote variable expansions unless you explicitly need word splitting.


2. Not Checking Command Success

Problem

# Wrong
cd /some/directory
rm -rf *  # DANGEROUS if cd fails!

Consequence

Commands execute even if previous commands fail, potentially catastrophic.

Solution

# Right
cd /some/directory || exit 1
rm -rf *

# Or use set -e
set -e
cd /some/directory
rm -rf *

# Or check explicitly
if ! cd /some/directory; then
    echo "Failed to change directory" >&2
    exit 1
fi
rm -rf *

3. Using [ ] with Bash Features

Problem

# Wrong (== not POSIX, may fail in sh)
if [ "$var" == "value" ]; then
    echo "match"
fi

Solution

# POSIX sh - use single =
if [ "$var" = "value" ]; then
    echo "match"
fi

# Or use bash [[ ]] (bash only)
if [[ "$var" == "value" ]]; then
    echo "match"
fi

4. Useless Use of cat (UUOC)

Problem

# Wrong - unnecessary cat
cat file.txt | grep pattern
cat file.txt | awk '{print $1}'

Consequence

Wastes a process, less efficient.

Solution

# Right
grep pattern file.txt
awk '{print $1}' file.txt

# Or use redirection
< file.txt grep pattern

5. Not Using -r with read

Problem

# Wrong
while read line; do
    echo "$line"
done < file

Consequence

Backslashes are interpreted, leading character may be removed.

Solution

# Right
while IFS= read -r line; do
    echo "$line"
done < file
  • -r prevents backslash interpretation
  • IFS= prevents leading/trailing whitespace trimming

6. Testing $? After Multiple Commands

Problem

# Wrong
command1
command2
if [ $? -eq 0 ]; then  # Tests command2, not command1!
    echo "Success"
fi

Solution

# Right - test immediately
command1
if [ $? -eq 0 ]; then
    echo "command1 succeeded"
fi

# Better - test directly
if command1; then
    echo "Success"
fi

7. Arrays in POSIX sh Scripts

Problem

#!/bin/sh
# Wrong - arrays not in POSIX sh
array=(one two three)
echo "${array[0]}"

Solution

# Use bash
#!/bin/bash
array=(one two three)
echo "${array[0]}"

# Or use POSIX alternatives
set -- one two three
echo "$1"

8. Not Declaring Functions Before Use

Problem

# Wrong - function not defined yet
my_function

my_function() {
    echo "Hello"
}

Solution

# Right - define first
my_function() {
    echo "Hello"
}

my_function

9. Using eval Unsafely

Problem

# DANGEROUS
user_input="$1"
eval "$user_input"  # Command injection risk!

Consequence

Security vulnerability - arbitrary code execution.

Solution

# Avoid eval when possible
# If necessary, sanitize input thoroughly
# Or use safer alternatives

# Example: dynamic variable names
var_name="my_var"
# Don't: eval "echo \$$var_name"
# Do: Use indirect expansion (bash)
echo "${!var_name}"

10. Forgetting set -u

Problem

# Wrong - typo goes unnoticed
nmae="John"  # Typo
echo "Hello, $name"  # Prints "Hello, " (empty)

Solution

# Right - use set -u
set -u
nmae="John"  # Typo
echo "Hello, $name"  # Error: name: unbound variable

11. Incorrect String Comparison

Problem

# Wrong - numeric comparison on strings
if [ "$version" -gt "2.0" ]; then
    echo "New version"
fi

Solution

# Right - string comparison
if [ "$version" = "2.0" ]; then
    echo "Exact match"
fi

# Or use proper version comparison
if [[ "$version" > "2.0" ]]; then
    echo "Greater"
fi

12. Not Handling Spaces in Filenames

Problem

# Wrong
for file in $(ls *.txt); do
    echo "$file"
done

Consequence

Files with spaces break into multiple items.

Solution

# Right - use glob directly
for file in *.txt; do
    echo "$file"
done

# Or use find with -print0
while IFS= read -r -d '' file; do
    echo "$file"
done < <(find . -name "*.txt" -print0)

13. Backticks Instead of $()

Problem

# Deprecated
result=`command arg1 arg2`

Solution

# Modern
result=$(command arg1 arg2)

Why

  • Better nesting: $(cmd1 $(cmd2))
  • Better readability
  • Fewer escaping issues

14. Using = Instead of == in [[ ]]

Not really a mistake, but inconsistent:

# Both work in [[ ]]
[[ "$var" = "value" ]]   # POSIX style (works)
[[ "$var" == "value" ]]  # Bash style (also works)

# Only = works in [ ]
[ "$var" = "value" ]     # Works
[ "$var" == "value" ]    # May fail in POSIX sh

Recommendation: Use = for portability, or stick to == in bash with [[ ]].


15. Not Quoting $@

Problem

# Wrong
script.sh "$@"  # Right
command $@      # Wrong if args have spaces

Solution

# Right
command "$@"  # Preserves argument boundaries

16. Using ls to Process Files

Problem

# Wrong
files=$(ls *.txt)
for file in $files; do
    process "$file"
done

Issues

  • Breaks on spaces
  • Breaks on newlines in filenames
  • Breaks on glob characters

Solution

# Right
for file in *.txt; do
    process "$file"
done

# Or with find
find . -name "*.txt" -exec process {} \;

17. Incorrect Exit Codes

Problem

# Wrong
function check_file() {
    if [ -f "$1" ]; then
        echo "File exists"
        return 1  # Success should be 0!
    fi
    return 0
}

Solution

# Right - 0 is success, non-zero is failure
function check_file() {
    if [ -f "$1" ]; then
        echo "File exists"
        return 0
    fi
    return 1
}

18. Using -a and -o in [ ]

Problem

# Deprecated and error-prone
[ "$a" = "x" -a "$b" = "y" ]
[ "$a" = "x" -o "$b" = "y" ]

Solution

# Right - use && and ||
[ "$a" = "x" ] && [ "$b" = "y" ]
[ "$a" = "x" ] || [ "$b" = "y" ]

# Or use [[ ]] in bash
[[ "$a" = "x" && "$b" = "y" ]]
[[ "$a" = "x" || "$b" = "y" ]]

19. Not Making Scripts Executable

Problem

# Wrong
bash script.sh  # Works but not ideal

Solution

# Right
chmod +x script.sh
./script.sh

And include proper shebang:

#!/usr/bin/env bash

20. Forgetting Final Newline

Problem

Some tools expect files to end with a newline.

Solution

Ensure your editor adds a final newline, or:

echo "" >> file

21. Using grep -q Without Knowing Implications

Problem

# Potentially inefficient
if [ "$(grep pattern file)" ]; then
    echo "Found"
fi

Solution

# Better - grep -q exits on first match
if grep -q pattern file; then
    echo "Found"
fi

22. Incorrect glob Pattern

Problem

# Wrong - doesn't match hidden files
for file in *; do
    process "$file"
done

Solution

# Include hidden files (bash)
shopt -s dotglob
for file in *; do
    process "$file"
done
shopt -u dotglob

# Or explicitly
for file in * .[!.]* ..?*; do
    [ -e "$file" ] && process "$file"
done

23. Not Handling Empty Globs

Problem

# Fails if no .txt files
for file in *.txt; do
    process "$file"  # Processes literal "*.txt"
done

Solution

# Bash - fail gracefully
shopt -s nullglob
for file in *.txt; do
    process "$file"
done
shopt -u nullglob

# POSIX - check existence
for file in *.txt; do
    [ -e "$file" ] || continue
    process "$file"
done

24. Not Sanitizing Input

Problem

# Dangerous
rm -rf "/$1"  # What if $1 is empty or manipulated?

Solution

# Safer
if [ -z "$1" ]; then
    echo "Error: No argument provided" >&2
    exit 1
fi

# Validate
case "$1" in
    /*)
        echo "Error: Absolute paths not allowed" >&2
        exit 1
        ;;
esac

rm -rf "$1"

25. Using -e for File Existence

Not a mistake, but be specific:

[ -e "$file" ]  # Exists (any type)
[ -f "$file" ]  # Regular file
[ -d "$file" ]  # Directory
[ -L "$file" ]  # Symbolic link
[ -r "$file" ]  # Readable
[ -w "$file" ]  # Writable
[ -x "$file" ]  # Executable

Quick Checklist

Before running a script, verify:

  • Proper shebang (#!/bin/bash or #!/bin/sh)
  • set -euo pipefail (strict mode)
  • All variables quoted
  • Error handling for critical commands
  • Using $() not backticks
  • Not using ls for file processing
  • Functions defined before use
  • Proper exit codes (0 = success)
  • Input validation
  • ShellCheck passes

Resources

  • ShellCheck - Catches most of these
  • Bash Pitfalls
  • POSIX Shell

tile.json