A Beginner's Guide to Shell Scripting: Key Concepts, Examples, and Best Practices

Shell scripting is a powerful tool for automating tasks in a Linux environment. It enables developers and system administrators to execute a series of commands efficiently, saving time and reducing human error. In this blog, we’ll cover the essentials of shell scripting, provide examples, and highlight its practical applications.


What is a Shell and Shell Scripting?

Shell

A shell is a Command Line Interface (CLI) that interprets and executes Linux commands. For example:

  • ls -l: Displays detailed information about files and directories.

  • df -h: Displays disk usage in a human-readable format.

  • top: Shows real-time system performance, including processes and memory usage.

Shell Script

A shell script is a file containing a sequence of shell commands, variables, functions, and control structures (e.g., loops, conditions). These scripts automate repetitive tasks.


Why Use Shell Scripting?

  1. Automation: Streamlines manual tasks such as server setup, software installation, deployment, and log management.

  2. Efficiency: Reduces execution time and human error.

  3. Reusability: Write once and use across different environments.

  4. Flexibility: Manage files, interact with databases, and handle system-level operations.


Getting Started with Shell Scripting

Shebang

Every shell script begins with a shebang:
#!/bin/bash
This specifies the interpreter (e.g., bash) to execute the script.

Executing a Shell Script

  1. sh <script_name>

  2. bash <script_name>

  3. ./<script_name> (Ensure the script has executable permissions: chmod +x <script_name>)


Core Concepts

Variables

Variables store values that can be reused throughout the script.
Example:

#!/bin/bash
NAME="John"
echo "Hello, $NAME!"

Arrays

Store multiple values in a single variable.
Example:

MOVIES=("RRR" "DjTillu" "Murari")
echo "First Movie: ${MOVIES[0]}"
echo "All Movies: ${MOVIES[@]}"

Conditions

Control the flow based on conditions.
Example:

#!/bin/bash
NUMBER=$1
if [ $NUMBER -gt 10 ]; then
    echo "Number is greater than 10"
else
    echo "Number is less than or equal to 10"
fi

Loops

Repeat tasks efficiently.
Example:

for i in {1..5}; do
    echo "Iteration: $i"
done

Real-Time Useful Commands

Here are some real-world shell commands that are useful for daily operations:

  1. File Management

    • cp -r source_dir/ target_dir/: Copy directories recursively.

    • rm -rf /tmp/*: Delete all files and directories in /tmp.

  2. Process and Memory Monitoring

    • ps aux: Show all running processes.

    • top | grep java: Monitor resource usage for Java processes.

  3. Networking

    • ping google.com: Check network connectivity.

    • netstat -tuln: Display active network connections.

  4. Disk Space Management

    • df -h /: Display available disk space in the root directory.

    • du -sh /path/to/dir: Show the size of a specific directory.

  5. Log Management

    • tail -f /var/log/syslog: Monitor a log file in real-time.

    • find /var/log -name "*.log" -type f -size +10M: Find log files larger than 10 MB.

  6. User Management

    • whoami: Show the current user.

    • sudo useradd new_user: Add a new user.

Practical Applications

Automating Server Setup

Example script for configuring a Node.js server:

#!/bin/bash

# Update and install dependencies
sudo apt update
sudo apt install -y nodejs npm

# Setup application
mkdir /var/myapp
cd /var/myapp
wget https://example.com/app.zip
unzip app.zip
npm install

# Start application as a service
cat <<EOF > /etc/systemd/system/myapp.service
[Unit]
Description=My Node.js App

[Service]
ExecStart=/usr/bin/node /var/myapp/app.js
Restart=always

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable myapp
sudo systemctl start myapp

Deployment Automation

Automate the deployment of a new application version:

#!/bin/bash
APP_DIR="/var/myapp"
NEW_VERSION="https://example.com/new_version.zip"

# Stop the server
sudo systemctl stop myapp

# Update code
rm -rf $APP_DIR/*
wget $NEW_VERSION -O app.zip
unzip app.zip -d $APP_DIR
npm install

# Restart the server
sudo systemctl start myapp

Old Log Deletion Use Case

Managing logs is a common use case in real-world systems. Here’s a script to delete old logs:

#!/bin/bash

LOG_DIR="/var/log/myapp" # Specify the log directory
RETENTION_DAYS=14       # Retain logs for 14 days

# Find and delete logs older than the retention period
find $LOG_DIR -name "*.log" -type f -mtime +$RETENTION_DAYS -exec rm {} \;
echo "Old logs deleted successfully from $LOG_DIR."

This script ensures your system remains clean and avoids storage issues due to accumulated logs.

Advanced Concepts

Error Handling

Errors are inevitable in shell scripts. Use exit codes to handle them.
Example:

#!/bin/bash
set -e  # Exit immediately if a command fails

if ! mkdir /var/test; then
    echo "Failed to create directory."
    exit 1
fi
echo "Directory created successfully."

Functions

Reuse blocks of code by defining functions.
Example:

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

Log Management

Rotate and delete old log files:

#!/bin/bash
LOG_DIR="/var/log/myapp"
find $LOG_DIR -name "*.log" -type f -mtime +14 -exec rm {} \;
echo "Old logs deleted."

Scheduling Tasks

Use crontab for scheduling.
Example:

# Run a script daily at midnight
0 0 * * * /path/to/script.sh

Best Practices

  1. Use Version Control: Store scripts in GitHub/GitLab for collaboration and backup.

  2. Write Modular Scripts: Break large scripts into smaller, reusable functions.

  3. Add Comments: Explain complex sections of code.

  4. Handle Errors Gracefully: Use set -e and proper error handling.

  5. Test Thoroughly: Validate scripts in a safe environment before production.