Shell scripting is how Linux sysadmins stop doing the same task twice. If you have ever run a sequence of commands more than once, that sequence belongs in a script. Bash scripts are plain text files with Linux commands — no compiler needed, no runtime to install. This guide teaches you real scripting from the ground up.
Your First Script
#!/bin/bash
# myscript.sh
echo "Hello, $(whoami)!"
echo "Today is: $(date +'%A, %B %d %Y')"
echo "Current directory: $(pwd)"
Save it, make it executable, and run it:
chmod +x myscript.sh
./myscript.sh
The #!/bin/bash shebang line tells the OS which interpreter to use. Always include it.
Variables
#!/bin/bash
NAME="alok"
BACKUP_DIR="/var/backups"
TODAY=$(date +%Y-%m-%d) # Command substitution
echo "User: $NAME"
echo "Backup dir: ${BACKUP_DIR}/daily"
echo "Date: $TODAY"
Rules for variables: no spaces around =; use ${VAR} when concatenating; single quotes suppress expansion.
Reading User Input
#!/bin/bash
read -p "Enter server hostname: " HOST
read -sp "Enter password: " PASS
echo
echo "Connecting to $HOST..."
Conditionals
#!/bin/bash
FILE="/etc/nginx/nginx.conf"
if [ -f "$FILE" ]; then
echo "Config found."
elif [ -d "/etc/nginx" ]; then
echo "Directory exists but config missing."
else
echo "Nginx not installed."
fi
Common test operators:
-f— file exists and is a regular file-d— directory exists-z "$VAR"— string is empty-n "$VAR"— string is not empty-eq,-ne,-gt,-lt— integer comparisons=,!=— string comparisons
if [ "$USER" = "root" ]; then
echo "Running as root."
fi
if [ $# -eq 0 ]; then
echo "Usage: $0 filename"
exit 1
fi
Loops
For Loop
for SERVER in web01 web02 db01; do
echo "Pinging $SERVER..."
ping -c 1 $SERVER &>/dev/null && echo " OK" || echo " UNREACHABLE"
done
for FILE in /var/log/*.log; do
echo "Processing: $FILE"
gzip "$FILE"
done
While Loop
COUNT=0
while [ $COUNT -lt 5 ]; do
echo "Count: $COUNT"
COUNT=$((COUNT + 1))
done
Functions
#!/bin/bash
log() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1"
}
backup_dir() {
local SRC="$1"
local DEST="$2"
log "Backing up $SRC to $DEST"
tar -czf "$DEST/backup-$(date +%Y%m%d).tar.gz" "$SRC"
log "Done."
}
backup_dir /etc/nginx /var/backups
Exit Codes and Error Handling
#!/bin/bash
set -e # Exit on any error
set -u # Treat unset variables as errors
set -o pipefail # Catch errors in pipes
cp /etc/hosts /backup/ || { echo "Backup failed!"; exit 1; }
systemctl restart nginx
if [ $? -ne 0 ]; then
echo "Nginx restart failed"
exit 1
fi
Practical Script: Disk Space Alert
#!/bin/bash
THRESHOLD=80
df -h | grep -vE "^(Filesystem|tmpfs)" | while read LINE; do
USAGE=$(echo "$LINE" | awk "{print $5}" | tr -d "%")
MOUNT=$(echo "$LINE" | awk "{print $6}")
if [ "$USAGE" -gt "$THRESHOLD" ]; then
echo "ALERT: $MOUNT is at ${USAGE}% on $(hostname)"
fi
done
Script Arguments
#!/bin/bash
ENVIRONMENT=$1
VERSION=$2
if [ -z "$ENVIRONMENT" ] || [ -z "$VERSION" ]; then
echo "Usage: $0 environment version"
exit 1
fi
echo "Deploying version $VERSION to $ENVIRONMENT"
# $0=script name, $1 $2...=arguments, $#=count, $@=all args
Summary
Shell scripting turns repetitive work into repeatable, reliable automation. Start small — convert your most common command sequences into scripts. Add error handling with set -e, use functions to keep code organized, and always test on a non-production system first. Over time, your script library becomes one of your most valuable tools as a sysadmin.