Fundamentals 9 min read

Boost Your Bash Scripts: Safety, Functions, and Advanced Tips

This article presents practical Bash scripting techniques—including safety flags, function definitions, variable annotations, modern command substitution, double‑bracket tests, powerful string manipulation, process substitution, here‑documents, built‑in variables, and debugging methods—to write more reliable and maintainable shell scripts.

ITPUB
ITPUB
ITPUB
Boost Your Bash Scripts: Safety, Functions, and Advanced Tips

Script Safety

Start every Bash script with strict error handling to avoid common pitfalls:

#!/bin/bash
set -o nounset   # Treat unset variables as an error
set -o errexit   # Exit immediately on command failure

These options prevent using undefined variables and silently ignoring failed commands, though some commands (e.g., mkdir -p, rm -f) can still suppress errors, and errexit may not catch every failure.

Script Functions

Define reusable functions to improve readability and modularity. Example of extracting comments:

ExtractBashComments(){ egrep "^#" }
cat myscript.sh | ExtractBashComments | wc
comments=$(ExtractBashComments < myscript.sh)

Other examples show summing lines and logging:

SumLines(){
  local sum=0 line=""
  while read line; do
    sum=$((sum + line))
  done
  echo $sum
}

log(){
  local prefix="[$(date +"%Y/%m/%d %H:%M:%S")]: "
  echo "${prefix}$@" >&2
}
log "INFO" "a message"

Keep most code inside functions; only global variables, constants, and the final call to main should remain at the top level.

Variable Annotations

Use local for function‑scoped variables and readonly for constants. Example:

# Define a default that can be overridden
readonly DEFAULT_VAL=${DEFAULT_VAL:-7}
myfunc(){
  local some_var=${DEFAULT_VAL}
  # ...
}

Attempting to modify a readonly variable triggers an error:

x=5
x=6
readonly x
x=7   # failure

Annotate all script variables with local or readonly whenever possible.

Modern Command Substitution

Prefer $(...) over backticks because it nests cleanly and avoids escaping issues. Example:

echo "A-$(echo B-$(echo C-$(echo D)))"

Double Brackets [[ ]] vs Single Brackets [ ]

Use [[ ... ]] for safer tests, pattern matching, and extended syntax. Examples:

# Single brackets (traditional)
[ "${name}" > "a" -o ${name} < "m" ]

# Double brackets (preferred)
[[ "${name}" > "a" && "${name}" < "m" ]]

# Globbing and regex examples
[[ "$t" == abc* ]]      # globbing (true)
[[ "$t" =~ abc[0-9]+ ]] # regex (true)

Note: From Bash 3.2 onward, quoting the pattern disables globbing and regex evaluation; store complex patterns in variables if they contain spaces.

String Operations

Bash provides length, slicing, replacement, and deletion operators:

f="path1/path2/file.ext"
len=${#f}                     # length = 20
slice1=${f:6}                # "path2/file.ext"
slice2=${f:6:5}            # "path2"
slice3=${f: -8}            # "file.ext"
pos=6; len=5; slice4=${f:${pos}:${len}} # "path2"

# Replacement
single_subst=${f/path?/x}   # "x/path2/file.ext"
global_subst=${f//path?/x} # "x/x/file.ext"

# Deletion (globbing)
extension=${f#*.}          # "ext"
filename=${f##*/}           # "file.ext"
dirname=${f%/*}           # "path1/path2"
root=${f%%/*}               # "path1"

Avoid Temporary Files

Use process substitution <( ... ) to feed command output where a filename is required:

# Compare two web pages without creating temp files
bash -c "diff <(wget -O - url1) <(wget -O - url2)"

Here Documents

Embed multi‑line strings directly into a script:

command << MARKER
...${var}
$(cmd)...
MARKER

Quote the delimiter to suppress variable expansion:

command <<'MARKER'
no substitution here
MARKER

Built‑in Variables

Built‑in variables illustration
Built‑in variables illustration

Key points: use $@ (quoted) instead of $* for proper handling of arguments containing spaces.

Debugging

Syntax check: bash -n myscript.sh Trace execution:

bash -v myscript.sh   # verbose
bash -x myscript.sh   # execution trace

Set these options permanently at the script top with set -o verbose and set -o xtrace, useful for remote execution.

When Not to Use Bash

Your script grows to hundreds of lines.

You need complex data structures beyond arrays.

Escaping becomes overly complicated.

Heavy string manipulation dominates.

Little interaction with other programs or pipelines.

Performance concerns arise.

In such cases, consider a higher‑level language like Python or Ruby.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

bashFunctionsShell Scriptingstring-manipulationscript safety
ITPUB
Written by

ITPUB

Official ITPUB account sharing technical insights, community news, and exciting events.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.