CIS238RH | RHEL System Administration 2
Mesa Community College
Create scripts with proper structure, shebang, and execute permissions
Define variables, use special parameters, and read user input
Use for and while loops to repeat commands efficiently
Use if statements, test conditions, and shell expansions
A shell script is a text file containing a sequence of commands that the shell executes. Scripts automate tasks you would otherwise type manually.
Run multiple commands with a single execution
Write once, run many times on different systems
Same steps every time, reducing human error
Script itself documents the procedure
# Create a script file
[student@server ~]$ vim hello.sh
#!/bin/bash
# My first shell script
echo "Hello, World!"
echo "Today is $(date)"
echo "You are logged in as: $USER"
echo "Your home directory is: $HOME"
# Make executable and run
[student@server ~]$ chmod +x hello.sh
[student@server ~]$ ./hello.sh
Hello, World!
Today is Mon Jan 15 10:30:45 EST 2024
You are logged in as: student
Your home directory is: /home/student
The shebang (#!) on the first line specifies which interpreter executes the script. Must be line 1, column 1.
#!/bin/bash # Use Bash (most common)
#!/bin/sh # POSIX shell (portable)
#!/usr/bin/python3 # Python script
#!/usr/bin/env bash # Find bash in PATH
$ ./script.sh$ bash script.sh# Method 1: Make executable and run
[student@server ~]$ chmod +x script.sh
[student@server ~]$ ./script.sh
# Method 2: Call interpreter explicitly
[student@server ~]$ bash script.sh
[student@server ~]$ bash -x script.sh # Debug mode
# Method 3: Source (runs in current shell)
[student@server ~]$ source script.sh
[student@server ~]$ . script.sh
| Method | Execute Permission | New Shell? | Use Case |
|---|---|---|---|
| ./script.sh | Required | Yes | Normal execution |
| bash script.sh | Not needed | Yes | Testing |
| source script.sh | Not needed | No | Set environment |
Variables store data for use in scripts. No spaces around =, case-sensitive names.
# Defining variables (NO spaces around =)
NAME="John"
AGE=25
FILE_PATH="/var/log/messages"
# Using variables
echo "Hello, $NAME"
echo "Log file: $FILE_PATH"
# Curly braces for clarity
echo "Files: ${FILE_PATH}s"
echo "Name length: ${#NAME}"
# Command output in a variable
TODAY=$(date +%Y-%m-%d)
FILES=$(ls /etc/*.conf | wc -l)
echo "Today: $TODAY, Config files: $FILES"
NAME = "John" won't work.# Double quotes - variables ARE expanded
NAME="World"
echo "Hello, $NAME" # Output: Hello, World
# Single quotes - literal (NO expansion)
echo 'Hello, $NAME' # Output: Hello, $NAME
# Escape special characters
echo "The price is \$5.00"
echo 'The price is $5.00'
# Spaces in values - quotes required
GREETING="Hello World" # Correct
# Files with spaces
FILE="my document.txt"
cat "$FILE" # Quotes preserve the space
#!/bin/bash
echo "Script name: $0"
echo "First argument: $1"
echo "Number of arguments: $#"
echo "All arguments: $@"
[student@server ~]$ ./args.sh hello world
Script name: ./args.sh
First argument: hello
Number of arguments: 2
All arguments: hello world
#!/bin/bash
# Simple read
echo "What is your name?"
read NAME
echo "Hello, $NAME!"
# Read with prompt (-p)
read -p "Enter your age: " AGE
# Silent read for passwords (-s)
read -sp "Enter password: " PASSWORD
echo
# Read with timeout (-t)
read -t 5 -p "Quick! Enter something: " QUICK
# Default value pattern
read -p "Enter directory [/tmp]: " DIR
DIR=${DIR:-/tmp} # Use /tmp if empty
Every command returns an exit status (0-255). 0 = success, non-zero = failure.
[student@server ~]$ ls /etc/passwd
[student@server ~]$ echo $?
0 # Success
[student@server ~]$ ls /nonexistent
[student@server ~]$ echo $?
2 # Failure
# Setting exit status in scripts
#!/bin/bash
if [ ! -f "$1" ]; then
echo "Error: File not found" >&2
exit 1
fi
echo "Processing $1..."
exit 0
# && (AND) - run second only if first succeeds
$ mkdir /tmp/test && echo "Created"
# || (OR) - run second only if first fails
$ mkdir /tmp/test || echo "Failed"
# Combining && and ||
$ ping -c 1 server && echo "Up" || echo "Down"
# Semicolon ; runs regardless of status
$ echo "Start"; sleep 2; echo "Done"
# Practical examples
cd /var/log && tail messages
[ -d /backup ] || mkdir /backup
&& = "AND then" (if OK). || = "OR else" (if failed).#!/bin/bash
# Basic if
if [ "$USER" = "root" ]; then
echo "You are root"
fi
# if-else
if [ -f "/etc/passwd" ]; then
echo "File exists"
else
echo "File not found"
fi
# if-elif-else
if [ "$1" = "start" ]; then
echo "Starting..."
elif [ "$1" = "stop" ]; then
echo "Stopping..."
else
echo "Usage: $0 {start|stop}"
exit 1
fi
["$USER"="root"] won't work.[ -f "/etc/passwd" ] && echo "File exists"
[ -z "$VAR" ] && echo "VAR is empty"
[ "$COUNT" -gt 10 ] && echo "More than 10"
#!/bin/bash
# Loop through a list
for NAME in Alice Bob Charlie; do
echo "Hello, $NAME"
done
# Loop through files
for FILE in /etc/*.conf; do
echo "Config: $FILE"
done
# Loop through command output
for USER in $(cut -d: -f1 /etc/passwd); do
echo "User: $USER"
done
# C-style for loop
for ((i=1; i<=5; i++)); do
echo "Count: $i"
done
#!/bin/bash
# Basic while loop
COUNT=1
while [ $COUNT -le 5 ]; do
echo "Count: $COUNT"
((COUNT++))
done
# Read file line by line
while read LINE; do
echo "Line: $LINE"
done < /etc/hosts
# Infinite loop with break
while true; do
read -p "Command (quit to exit): " CMD
[ "$CMD" = "quit" ] && break
echo "You entered: $CMD"
done
Brace expansion generates multiple strings from a pattern before other expansions.
# List expansion
$ echo {a,b,c}
a b c
$ echo file{1,2,3}.txt
file1.txt file2.txt file3.txt
# Sequence expansion
$ echo {1..5}
1 2 3 4 5
$ echo {a..e}
a b c d e
# Practical uses
mkdir -p project/{src,bin,doc}
cp config.conf{,.backup}
touch file{1..10}.txt
mv report.{txt,md}
# Modern syntax: $(command)
$ echo "Today is $(date +%A)"
Today is Monday
$ FILES=$(ls *.txt | wc -l)
$ echo "Found $FILES text files"
# Nested command substitution
$ echo "Home: $(dirname $(readlink -f ~/.bashrc))"
# In conditions
if [ $(id -u) -eq 0 ]; then
echo "Running as root"
fi
# In loops
for PKG in $(rpm -qa | grep httpd); do
echo "Installed: $PKG"
done
# Arithmetic expansion $(( ))
$ echo $((5 + 3))
8
$ echo $((10 / 3)) # Integer division
3
$ echo $((10 % 3)) # Modulo
1
# Variables in arithmetic
A=5; B=3
echo $((A + B)) # 8
echo $((A ** 2)) # 25 (exponent)
# Increment/decrement
((COUNT++))
((COUNT += 5))
# In scripts
TOTAL=0
for NUM in 1 2 3 4 5; do
((TOTAL += NUM))
done
echo "Sum: $TOTAL"
#!/bin/bash
# backup.sh - Backup home directory
set -e # Exit on error
DEST="${1:-/backup}"
[ -d "$DEST" ] || { echo "Error: $DEST not found" >&2; exit 1; }
tar -czf "$DEST/home-$(date +%Y%m%d).tar.gz" "$HOME"
Scripts: Start with #!/bin/bash, chmod +x, run with ./script.sh
Variables: NAME=value (no spaces), use "$NAME", special: $1 $# $?
Loops: for VAR in LIST; do...done, while COND; do...done
Conditionals: if [ test ]; then...fi, tests: -f -d -eq -lt, && ||
if/then/else statement that executes different commands based on a condition being true or false.Next: Using Regular Expressions for Practical Applications