Bash scripting—an old school yet a powerhouse language, often unnoted in the high-speed coding era—still holds its ground when it comes to automating tasks, manipulating data and system administration. This post is all about leveraging Bash scripting skills from ‘Intermediate’ to ‘Advanced’. We dive into advanced techniques, notable gotchas and pitfalls, and reveal coding examples that will polish your scripting skills.

Let’s start with an essential quote by the acclaimed systems architect, Brian Fox, creator of Bash:

“When something goes wrong with Bash, it’s often little more than a simple error that takes only moments to correct.”

Advanced Patterns & Text Manipulations

In veteran hands, Bash can model complex data structures and advanced text manipulations. One way is through the use of positional parameters, like $1, $2, etc.

# Code example for positional parameters
#!/bin/bash
echo "Script name: $0"
echo "First parameter: $1"
echo "Second parameter: $2"
echo "All parameters: $@"

Another fascinating option is the Regular Expression (RegEx) matches from Bash version 3.0 onwards. A use case, for demonstration, is validating usernames.

# Code example for username validation
#!/bin/bash 
read -p "Enter username: " username 
if [[ "$username" =~ ^[a-z_][a-z0-9_]{2,7}$ ]] 
then 
    echo "Username is valid." 
else 
    echo "Username is not valid." 
fi 

Trap Statements

Widely used, yet often misunderstood, trap commands define actions to trigger when the script receives specific signals. They help with an elegant exiting mechanism and cleaner script management. The code below enables debugging mode and sets a trap for exit signals.

#!/bin/bash
set -x
trap 'echo "Script is exiting"; exit' SIGINT SIGTERM
while true; do : ; done

Here Documents

Here Documents (<<) and Here Strings (<<<) fall under the redirection capabilities of Bash. They offer a convenient way to direct input from a data block. The following example demonstrates how to pass a SQL query from a Bash script to mysql client:

#!/bin/bash
DATABASE="SampleDB"
USERNAME="sampleUser"
PASSWORD="samplePass"
mysql -u $USERNAME -p $PASSWORD $DATABASE << EOF 
SELECT * 
FROM Employee 
WHERE Salary > 50000;
EOF

Trapped in a long line of command parameters? Make use of Here Strings for a cleaner and readable approach. An example from this Github repo demonstrates this:

#!/bin/bash
while IFS= read -r url
do
  /usr/bin/mpv --no-video "$url"
done <<< "$(/usr/bin/curl -s --unix-socket ~/.config/Qbit_manage/Sockets/Qbit.sock http://localhost/api/v2/torrents/info?hashes=$1 | \
  /usr/bin/jq -r '.[].content_path')"

Error Handling

Unlike other higher-level languages, Bash has a different approach to error handling. It doesn’t have an exception handling framework, but instead, uses exit statuses of each command. In an advanced scenario, any non-zero exit status can be trapped with the ‘ERR’ signal, and an error function can be implemented. A public gist demonstrates this:

#!/bin/bash
set -eE -o functrace

function err_handler {
    local err_status=$? 
    echo "The script exited abruptly with status: $err_status"
}

trap err_handler ERR

# Rest of the script

Fair Caveat

With great power comes great responsibility—Bash scripts can interact at a low-level with Unix system primitives, and an incorrect use can lead to system damages. Remember these critical pointers highlighted by Rich Cook:

  • Always defend your script from feeder mistakes
  • Be resilient against erroneous output from programs you call
  • Don’t forget to test your code extensively

To ensure you are well-prepared for the journey of advanced Bash scripting, consistently heed these facets. Happy scripting!

References

  1. Chet Ramey and Brian Fox, Bash Reference Manual, Free Software Foundation, 2000.
  2. William Shotts, The Linux Command Line, No Starch Press, 2012.
  3. Lhunath & GreyCat, Bash Guide for Beginners and Advanced Bash-Scripting Guide, tldp.org, 2008.