Shell Scripting Fundamentals

Why Learn Shell Scripting?
a shell script is a text file containing a list of commands which the shell executes in order
supports logic
can ask questions,d make decisions, and repeat tasks
Bash is Linux native tongue
  • universality - Bash is installed on almost every Linux box
  • glue - Bash is designed to 'glue' other programs together
    can take the output of ls, filtering it with grep, and passing it cp
  • efficiency - tasks involving file manipulation, process management, and system configuration
    faster to write and easier to read for other admins
Your First Shell Script: Shebang, Permissions, and Execution
a simple script
  1. create the fiile
    use text editor (nano or vim) to create a file named greet.sh
    nano greet.sh
  2. the Shebang
    first line of script declares the interpreter to be used
    #1/bin/bash
  3. the command
    on the second line add a command to file
    echo "Hello, sysadmin"
    save and exit (Ctrl+O, Enter, Ctrl+X)
    in nano save is done using 'Write Out' in the menu
  4. execution (permission problem)
    run the script
    ./greet.sh
    a permissions error will occur
    bash: ./greet.sh: Permission denied.
    must explicitly grant Execute permission
  5. fixing permissions
    see Changing Permissions: chmod with Symbolic and Numeric Modes
    chmod +x greet.sh
  6. success
    the script will now run
Variables and User Input
Defining Variables
define a variable by assigning a value to a name
there must be no spaces around the equals sign
name="Tracy"
Using Variables
modify greet.sh
#!/bin/bash 
name="Tracy" 
echo "Hello, $name."
$ tells bash to lookup value of name and make substitution

Read User Input
#!/bin/bash 
echo "What is your name?" 
read username 
echo "Hello, $username. Welcome to the terminal."
Environment Variables
system has a number of pre-assigned variables
  • $USER - current logged-in user
  • $HOME - path to home directory
  • $HOSTNAME - name of computer
echo "I am $USER running on $HOSTNAME"
Control Structures: if, elif, else
decision making
syntax in bash is sensitive to spaces

if statement
basic structure
if [ condition ]; then
     # do something 
else
     # do something else 
fi
the fi indicates then end of the if statement

The Test Command: []
validity test
must have a space between opening [, the test, and closing ]
#!/bin/bash 
filename="report.txt" 
if [ -f "$filename" ]; then 
    echo "The file exists." 
else
    echo "The file is missing."
fi
common test flags
  • -f - true if it's a file
  • -d - true if it's a directory
  • -e - true if it exists
  • -z - true if string is empty

special flags for comparing numbers
  • -eq - equal
  • -ne - not equal
  • -gt - greater than
  • -lt - less than

example
#!/bin/bash 
count=10 
if [ $count -gt 5 ]; then
     echo "The count is high." 
fi
Complex Logic: elif
#!/bin/bash 
echo "Enter a number:" 
read num 
if [ $num -gt 10 ]; then
    echo "That is a big number." 
elif [ $num -eq 10 ]; then 
    echo "That is exactly ten." 
else
    echo "That is a small number." 
fi
Loops: for, while, until
for loop
iterate a list
structure
for item in list; 
do
    command $item 
done
simple list example
#!/bin/bash 
for color in red green blue; do
    echo "The color is $color" 
done
processing files
#!/bin/bash
 # Rename all .txt files to .bak 
for file in *.txt; do
     echo "Backing up $file..."
     cp "$file" "$file.bak" 
done
while loop
#!/bin/bash 
count=1 
while [ $count -le 5 ]; do
     echo "Count is $count"
     # This increments the variable
     (count++)  
     # Pause for 1 second
     sleep 1      
done
until loop
#!/bin/bash 
# Wait for a file to appear 
until [ -f "stop.txt" ]; do
     echo "Waiting for stop.txt to be created..."
     sleep 2 
done 
echo "File found. Stopping."
Functions in Bash
Defining a Function
function log_message {
     echo "[$(date +%T)] $1" 
}
$1 is first arg passed to the function

Calling a Function
log_message "Starting backup..." 
sleep 1 
log_message "Backup complete."
Working with Command-Line Arguments
special variables for command line args
  • $0 - name of script
  • $1 - first arg
  • $2 - second arg
  • $# - toal number of arguments provided
  • $@ - list of all args
custom copy script example
save as smart_copy.sh
#!/bin/bash 
source_file=$1 
dest_file=$2 
if [ -z "$source_file" ]; then
     echo "Error: You must provide a source file."
     exit 1 
fi 
cp "$source_file" "$dest_file" 
echo "Copied $source_file to $dest_file."
run the script
./smart_copy.sh <source file> <destination file>
Exit Codes and Error Handling
Exit Codes
number returned when a command completes
  • 0 - success
  • none-zero (1-255) - failure
check exit code of last command using $?
ls /non_existent_folder
echo "The exit code was: $?"
Using Exit Codes in Logic
use code in if statements
if cp report.txt /backup/; then
     echo "Backup successful." 
else
     echo "Backup failed!" 
fi
Logical Operators (&& and ||)
use to chain commands
  • && (AND) - second command runs only if first command is successful
  • || (OR) - second command runs only if first command fails
Fail Fast (set -e)
#!/bin/bash 
set -e
...
set -e is an instruction telling bash to stop the script in any command returns a non-zero exit code
second line in script

Practical Scripting Examples: Automation and System Tasks
Automated Backup Script
script will create a compressed archive of a folder, timestamp it, and move it to a backup directory
#!/bin/bash 
# Configuration
SOURCE_DIR="/home/user/Documents" 
BACKUP_DIR="/var/backups/user_docs" 
DATE_STAMP=$(date +%Y-%m-%d_%H%M%S) 
FILENAME="docs_backup_$DATE_STAMP.tar.gz" 
# Ensure backup directory exists 
mkdir -p "$BACKUP_DIR" 
echo "Starting backup of $SOURCE_DIR..." 
# Create the archive # tar -c (create) -z (gzip) -f (file) 
tar -czf "$BACKUP_DIR/$FILENAME" "$SOURCE_DIR" 2>/dev/null
 # Check if tar succeeded 
if [ $? -eq 0 ]; then
     echo "Backup created successfully: $BACKUP_DIR/$FILENAME"
else
     echo "Backup failed!"
     exit 1 
fi 
# Cleanup: Delete backups older than 7 days 
find "$BACKUP_DIR" -name "docs_backup_*.tar.gz" -mtime +7 -delete 
echo "Old backups cleaned up."
System Monitor
checks disk space and memory usage
if disk space is low, it prints a warning
#!/bin/bash 
# thresholds
DISK_THRESHOLD=90 
# Get current usage of root partition (remove % sign) 
DISK_USAGE=$(df / | grep / | awk '{ print $5 }' | sed 's/%//g') 
echo "--- System Report ---" 
echo "Date: $(date)" 
echo "Disk Usage: $DISK_USAGE%" 
if [ "$DISK_USAGE" -gt "$DISK_THRESHOLD" ]; then
     echo "WARNING: Disk space is critically low!" 
else
     echo "Status: Disk space is okay." 
fi
 # Check Memory 
FREE_MEM=$(free -h | grep Mem | awk '{print $4}')
echo "Free Memory: $FREE_MEM"
Best Practices for Writing Maintainable Scripts
  1. use # to comment code
  2. use descriptive variable names
  3. always put quotes around variables used in file paths $filename
  4. use set -e and set -u - latter causes exit if undefined variable is used
  5. indentation
  6. avoid hard-coding paths
Summary
covered
  • Structure - #!/bin/bash
  • Variables -store data for reuse
  • Logic - decision making
  • Loops - for and while
  • Resilience - exit codes and -e flag

key points
  • Shebang - #!/bin/bash
  • Executable - using chmod +x script.sh
  • Variables - no spaces in declaration
  • Quotes - always double variables to safely handle spaces
  • read - captures input
  • if[ condition ]; then ... fi - basic decision structure
  • for i in list; do ... done - basic loop structure
  • $1, $2 - command line args
  • Exit Codes - 0 is success, anything else is failure
index