Chapter Objective: Write and run basic bash shell scripts using variables, positional parameters, exit status, conditionals, loops, and functions to automate repetitive command-line tasks.

Key concepts: #!/bin/bash, $1/$@, $?, if/test, for/while, functions

Why Write Shell Scripts?

A shell script is a text file containing a sequence of shell commands, run together as a single program. Anything you can type at the prompt, you can put in a script — the difference is repeatability: a script runs the same steps, in the same order, every time, without you retyping them.

🔵 Why It Matters System administration is full of repetitive, multi-step tasks — provisioning a new server, rotating logs, checking service health. Scripting turns a fragile sequence of manual steps into a reliable, testable, version-controllable tool.

Anatomy of a Script

#!/bin/bash
# This is a comment — bash ignores everything after #

echo "Starting backup..."
tar -czf /backups/etc-$(date +%Y%m%d).tar.gz /etc
echo "Backup complete."
LinePurpose
#!/bin/bashThe shebang — tells the system which interpreter should run this file
# commentExplanatory text, ignored when the script runs
Everything elseOrdinary shell commands, run top to bottom
# Make the script executable
chmod +x backup.sh

# Run it directly (relies on the shebang)
./backup.sh

# Or run it explicitly with bash, without needing execute permission
bash backup.sh
⚠️ Warning — The Shebang Must Be the Very First Line If anything — even a blank line — precedes #!/bin/bash, the system won't recognize it as a shebang and will fail to run the script as expected via ./scriptname.

Variables and Parameters

#!/bin/bash
# Assign a variable — no spaces around the equals sign
name="student"

# Reference it with a dollar sign
echo "Hello, $name"

# Curly braces avoid ambiguity when concatenating
echo "${name}s backup file"

Positional Parameters

Arguments passed to a script are available as numbered variables.

#!/bin/bash
# ./greet.sh Miguel Sales
echo "First argument: $1"     # Miguel
echo "Second argument: $2"    # Sales
echo "All arguments: $@"
echo "Number of arguments: $#"
echo "Script name: $0"
✅ Tip — Quote Your Variables "$1" (quoted) behaves predictably even if the argument contains spaces; unquoted $1 can split unexpectedly. Get in the habit of quoting variable references in scripts.

Exit Status

Every command returns a numeric exit status when it finishes: 0 means success, any nonzero value means some kind of failure. Scripts use this constantly to make decisions.

# Check the exit status of the last command
grep root /etc/passwd
echo $?
# 0 if found, 1 if not found

# Explicitly set a script's own exit status
#!/bin/bash
echo "Checking..."
exit 0   # success
🔵 Exam Note $? only reflects the immediately preceding command — check it right away, before running anything else, or the value you're reading will belong to a different command.

Conditionals

#!/bin/bash
if [ -f /etc/hostname ]; then
    echo "The file exists."
elif [ -d /etc/hostname ]; then
    echo "That's actually a directory."
else
    echo "Not found."
fi
TestTrue When
-f fileFile exists and is a regular file
-d dirDirectory exists
-z stringString is empty
-eq / -neNumeric equal / not equal
= / !=String equal / not equal
#!/bin/bash
# Numeric comparison example
count=5
if [ "$count" -gt 3 ]; then
    echo "count is greater than 3"
fi
⚠️ Warning — Spaces Inside [ ] Are Required [ -f /etc/hostname ] needs spaces immediately inside the brackets — [-f /etc/hostname] or [ -f /etc/hostname] will fail with a syntax error. The brackets are actually a command (test) that needs to be separated from its arguments.

Loops

#!/bin/bash
# for loop over a list of values
for user in alice bob carol; do
    echo "Creating account for $user"
done

# for loop over files matching a pattern
for file in /etc/*.conf; do
    echo "Found config: $file"
done

# while loop — runs as long as the condition is true
count=1
while [ "$count" -le 5 ]; do
    echo "Attempt $count"
    count=$((count + 1))
done
✅ Tip — $(( )) for Arithmetic Bash doesn't do math with plain + the way you'd expect. Wrap arithmetic expressions in $(( )), as in count=$((count + 1)), to get the calculation instead of string concatenation.

Functions

#!/bin/bash
# Define a function
greet() {
    echo "Hello, $1"
}

# Call it, passing an argument just like a script
greet "Miguel"

# Functions can return an exit status with return
check_file() {
    if [ -f "$1" ]; then
        return 0
    else
        return 1
    fi
}

if check_file /etc/hostname; then
    echo "File check passed"
fi
🔵 Note A function's return value is an exit status (0–255), not a general-purpose return value like in most programming languages. To send back actual data, have the function echo it and capture that with command substitution instead.

Key Terms for Chapter 1

shell script
A text file containing a sequence of shell commands, run together as a program
shebang
The #! line at the top of a script specifying which interpreter should run it
positional parameter
A numbered variable ($1, $2, ...) holding an argument passed to a script
exit status
The numeric result a command returns on completion; 0 means success
test / [ ]
The command (and its bracket shorthand) used to evaluate conditions in a script
function
A named, reusable block of shell commands, defined once and callable by name

Review Questions

  1. What is a shebang, and what happens if it isn't the very first line of a script?
  2. In a script called with ./deploy.sh production 2, what would $1 and $2 each contain?
  3. What does an exit status of 0 conventionally mean, and how would you check the exit status of the last command you ran?
  4. What is wrong with writing a conditional as if [-f /etc/hostname]; then?
  5. What is the difference between a for loop and a while loop, in terms of when each one stops?
  6. Why doesn't count = count + 1 work the way you might expect in bash, and what syntax fixes it?
  7. How does a bash function send back an actual piece of data (like a string) to the code that called it, given that return only supports numeric exit statuses?