Home/Blog/Automation/How to Write a Script: Beginner's Guide to Scripting
Automation

How to Write a Script: Beginner's Guide to Scripting

How to Write a Script: Beginner's Guide to Scripting

What Is a Script?

A script is a file containing a sequence of commands that a computer executes automatically. Instead of typing commands one by one, you write them in a file, and the computer runs them in order. Scripts automate repetitive tasks, from simple file operations to complex system administration workflows.

Think of a script as a recipe: you write down the steps once, and anyone (or any computer) can follow them to achieve the same result. This is the foundation of automation in IT, DevOps, and software development.

Scripts vs. Programs: What's the Difference?

While the terms are sometimes used interchangeably, there are key differences:

AspectScriptsCompiled Programs
ExecutionInterpreted line-by-lineCompiled to machine code first
SpeedSlower executionFaster execution
DevelopmentQuick to write and testLonger development cycle
Use CaseAutomation, glue codeApplications, system software
ExamplesBash, Python, PowerShellC, C++, Rust, Go

Scripts excel at automating tasks, connecting systems, and rapid prototyping. When you need to automate something quickly, scripting is usually the answer.

Why Learn Scripting?

Scripting skills are valuable across many roles:

For System Administrators:

  • Automate user account creation and management
  • Schedule backups and maintenance tasks
  • Monitor system health and generate alerts
  • Deploy software across multiple servers

For Developers:

  • Automate build and deployment processes
  • Create development environment setup scripts
  • Generate boilerplate code and project structures
  • Run automated tests

For Data Analysts:

  • Process and transform data files
  • Automate report generation
  • Schedule data imports and exports
  • Clean and validate datasets

For Security Professionals:

  • Automate security scans and audits
  • Parse and analyze log files
  • Create incident response automation
  • Generate compliance reports

Choosing a Scripting Language

The best scripting language depends on your operating system, use case, and existing skills.

Bash (Linux/macOS)

Bash (Bourne Again Shell) is the default shell on most Linux distributions and macOS. It's ideal for:

  • System administration on Unix-like systems
  • File and directory manipulation
  • Text processing with tools like grep, sed, and awk
  • Automating command-line workflows
#!/bin/bash
# Simple backup script

SOURCE="/home/user/documents"
BACKUP="/backup/documents-$(date +%Y%m%d).tar.gz"

echo "Starting backup..."
tar -czf "$BACKUP" "$SOURCE"
echo "Backup complete: $BACKUP"

Pros: Pre-installed on most systems, excellent for system tasks, pipes and redirects are powerful Cons: Syntax can be cryptic, limited data structures, not ideal for complex logic

PowerShell (Windows)

PowerShell is Microsoft's modern shell and scripting language. It's built on .NET and works with objects rather than text:

  • Windows system administration
  • Active Directory management
  • Azure and Microsoft 365 automation
  • Cross-platform (PowerShell Core runs on Linux/macOS)
# Get all stopped services and start them
Get-Service | Where-Object {$_.Status -eq "Stopped"} | Start-Service

# Create a new user in Active Directory
New-ADUser -Name "John Doe" -GivenName "John" -Surname "Doe" `
    -SamAccountName "jdoe" -UserPrincipalName "[email protected]" `
    -Path "OU=Users,DC=domain,DC=com" -AccountPassword (ConvertTo-SecureString "P@ssw0rd" -AsPlainText -Force) `
    -Enabled $true

Pros: Object-oriented output, excellent Windows integration, strong typing available Cons: Verbose syntax, learning curve for object pipeline

Python

Python is a general-purpose language that excels at scripting due to its readability and extensive libraries:

  • Cross-platform automation
  • Data processing and analysis
  • Web scraping and API integration
  • Complex logic and algorithms
#!/usr/bin/env python3
"""Organize files by extension into folders."""

import os
import shutil
from pathlib import Path

def organize_downloads(directory):
    """Move files into folders based on their extension."""
    extensions = {
        'Images': ['.jpg', '.jpeg', '.png', '.gif', '.svg'],
        'Documents': ['.pdf', '.doc', '.docx', '.txt', '.xlsx'],
        'Videos': ['.mp4', '.avi', '.mkv', '.mov'],
        'Archives': ['.zip', '.tar', '.gz', '.rar']
    }

    for file in Path(directory).iterdir():
        if file.is_file():
            for folder, exts in extensions.items():
                if file.suffix.lower() in exts:
                    dest = Path(directory) / folder
                    dest.mkdir(exist_ok=True)
                    shutil.move(str(file), str(dest / file.name))
                    print(f"Moved {file.name} to {folder}/")
                    break

if __name__ == "__main__":
    organize_downloads("/home/user/Downloads")

Pros: Readable syntax, massive library ecosystem, cross-platform, great for complex tasks Cons: Requires installation, slower than compiled languages

How to Write Your First Script

Let's walk through writing a script step by step, using Bash as an example.

Step 1: Create the Script File

Open a text editor and create a new file. Script files typically have extensions that indicate their language:

  • Bash: .sh
  • Python: .py
  • PowerShell: .ps1
# Create a new file
touch my_first_script.sh

# Open in your editor
nano my_first_script.sh

Step 2: Add the Shebang Line

The first line of a script should be the shebang (or hashbang), which tells the system which interpreter to use:

#!/bin/bash

Common shebangs:

  • #!/bin/bash - Bash shell
  • #!/usr/bin/env python3 - Python 3 (portable)
  • #!/usr/bin/env node - Node.js

Step 3: Write Your Commands

Add the commands you want to execute. Start simple:

#!/bin/bash

# My first script
# This script displays system information

echo "=== System Information ==="
echo "Hostname: $(hostname)"
echo "User: $(whoami)"
echo "Date: $(date)"
echo "Uptime: $(uptime -p)"
echo "========================="

Step 4: Make It Executable

Before running your script, you need to make it executable:

chmod +x my_first_script.sh

Step 5: Run Your Script

Execute your script:

./my_first_script.sh

Output:

=== System Information ===
Hostname: server01
User: admin
Date: Fri Jan 3 10:30:00 UTC 2025
Uptime: up 15 days, 4 hours
===========================

Essential Scripting Concepts

Variables

Variables store data for reuse throughout your script:

# Bash variables
NAME="John"
AGE=30
echo "Hello, $NAME. You are $AGE years old."

# Command output in a variable
CURRENT_DIR=$(pwd)
FILE_COUNT=$(ls | wc -l)
# Python variables
name = "John"
age = 30
print(f"Hello, {name}. You are {age} years old.")

# Store command output
import subprocess
current_dir = subprocess.check_output(['pwd']).decode().strip()

Conditional Logic (If Statements)

Make decisions in your scripts:

#!/bin/bash

FILE="/etc/passwd"

if [ -f "$FILE" ]; then
    echo "$FILE exists"
else
    echo "$FILE does not exist"
fi

# Check disk usage
USAGE=$(df / | tail -1 | awk '{print $5}' | tr -d '%')
if [ "$USAGE" -gt 80 ]; then
    echo "WARNING: Disk usage is above 80%"
fi
import os

file_path = "/etc/passwd"

if os.path.exists(file_path):
    print(f"{file_path} exists")
else:
    print(f"{file_path} does not exist")

Loops

Repeat actions multiple times:

#!/bin/bash

# For loop - iterate over a list
for server in web01 web02 web03; do
    echo "Pinging $server..."
    ping -c 1 "$server"
done

# While loop - repeat until condition is false
COUNT=1
while [ $COUNT -le 5 ]; do
    echo "Iteration $COUNT"
    COUNT=$((COUNT + 1))
done

# Process each line in a file
while read -r line; do
    echo "Processing: $line"
done < servers.txt
# For loop
servers = ['web01', 'web02', 'web03']
for server in servers:
    print(f"Pinging {server}...")

# While loop
count = 1
while count <= 5:
    print(f"Iteration {count}")
    count += 1

# Process file lines
with open('servers.txt', 'r') as f:
    for line in f:
        print(f"Processing: {line.strip()}")

Functions

Organize code into reusable blocks:

#!/bin/bash

# Define a function
backup_directory() {
    local source=$1
    local dest=$2

    if [ -d "$source" ]; then
        tar -czf "$dest" "$source"
        echo "Backup created: $dest"
        return 0
    else
        echo "Error: $source does not exist"
        return 1
    fi
}

# Call the function
backup_directory "/var/log" "/backup/logs-$(date +%Y%m%d).tar.gz"
def backup_directory(source: str, dest: str) -> bool:
    """Create a compressed backup of a directory."""
    import tarfile
    import os

    if os.path.isdir(source):
        with tarfile.open(dest, "w:gz") as tar:
            tar.add(source)
        print(f"Backup created: {dest}")
        return True
    else:
        print(f"Error: {source} does not exist")
        return False

# Call the function
backup_directory("/var/log", "/backup/logs-20250103.tar.gz")

Error Handling

Handle errors gracefully to make scripts robust:

#!/bin/bash
set -e  # Exit on any error
set -u  # Treat unset variables as errors

# Check if command succeeded
if ! command -v python3 &> /dev/null; then
    echo "Error: Python 3 is not installed"
    exit 1
fi

# Trap errors
cleanup() {
    echo "Cleaning up temporary files..."
    rm -f /tmp/script_temp_*
}
trap cleanup EXIT
import sys

try:
    with open('config.json', 'r') as f:
        config = json.load(f)
except FileNotFoundError:
    print("Error: config.json not found")
    sys.exit(1)
except json.JSONDecodeError as e:
    print(f"Error: Invalid JSON in config file: {e}")
    sys.exit(1)

Learn more about Python error handling in our guide: Python Try Except Explained.

Script Best Practices

1. Add Comments

Document what your script does and why:

#!/bin/bash
# ==============================================================================
# Script Name: backup_databases.sh
# Description: Creates daily backups of all MySQL databases
# Author: Your Name
# Date: 2025-01-03
# Usage: ./backup_databases.sh [--full|--incremental]
# ==============================================================================

# Configuration
BACKUP_DIR="/backup/mysql"  # Where to store backups
RETENTION_DAYS=30           # How long to keep backups

2. Use Meaningful Variable Names

# Bad
d="/backup"
n=30

# Good
BACKUP_DIRECTORY="/backup"
RETENTION_DAYS=30

3. Handle Arguments

Accept command-line arguments for flexibility:

#!/bin/bash

# Default values
VERBOSE=false
OUTPUT_FILE=""

# Parse arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        -v|--verbose)
            VERBOSE=true
            shift
            ;;
        -o|--output)
            OUTPUT_FILE="$2"
            shift 2
            ;;
        -h|--help)
            echo "Usage: $0 [-v] [-o output_file]"
            exit 0
            ;;
        *)
            echo "Unknown option: $1"
            exit 1
            ;;
    esac
done

4. Validate Input

Never trust user input:

#!/bin/bash

# Validate required argument
if [ -z "$1" ]; then
    echo "Error: Please provide a filename"
    exit 1
fi

# Validate file exists
if [ ! -f "$1" ]; then
    echo "Error: File '$1' not found"
    exit 1
fi

# Validate numeric input
if ! [[ "$2" =~ ^[0-9]+$ ]]; then
    echo "Error: Second argument must be a number"
    exit 1
fi

5. Log Output

Record what your script does:

#!/bin/bash

LOG_FILE="/var/log/my_script.log"

log() {
    local level=$1
    local message=$2
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $message" | tee -a "$LOG_FILE"
}

log "INFO" "Script started"
log "INFO" "Processing files..."
log "ERROR" "Failed to connect to database"
log "INFO" "Script completed"

6. Test Before Production

  • Test in a development environment first
  • Use set -x in Bash to see commands as they execute
  • Start with echo before destructive commands
  • Create backups before modifying data
#!/bin/bash

# Dry run mode - echo instead of execute
DRY_RUN=${DRY_RUN:-false}

delete_old_files() {
    if [ "$DRY_RUN" = true ]; then
        echo "[DRY RUN] Would delete: $1"
    else
        rm -f "$1"
    fi
}

Scheduling Scripts with Cron

Once you've written a script, you'll often want to run it automatically. On Linux/macOS, use cron to schedule scripts:

# Edit your crontab
crontab -e

# Run backup script daily at 2 AM
0 2 * * * /home/user/scripts/backup.sh

# Run cleanup every Sunday at midnight
0 0 * * 0 /home/user/scripts/cleanup.sh

# Run health check every 5 minutes
*/5 * * * * /home/user/scripts/healthcheck.sh

Use our Cron Expression Builder to create and validate cron schedules.

Common Scripting Mistakes to Avoid

1. Not Quoting Variables

# Wrong - breaks with spaces in filename
rm $FILE

# Right - handles spaces correctly
rm "$FILE"

2. Ignoring Exit Codes

# Wrong - continues even if command fails
cp source dest
process dest

# Right - check for errors
cp source dest || { echo "Copy failed"; exit 1; }
process dest

3. Hardcoding Values

# Wrong - hardcoded paths
tar -czf /backup/data.tar.gz /var/data

# Right - use variables
BACKUP_DIR="${BACKUP_DIR:-/backup}"
SOURCE_DIR="${SOURCE_DIR:-/var/data}"
tar -czf "$BACKUP_DIR/data.tar.gz" "$SOURCE_DIR"

4. Running as Root Unnecessarily

Only use elevated privileges when absolutely necessary:

#!/bin/bash

# Check if running as root when needed
if [ "$EUID" -ne 0 ]; then
    echo "This script requires root privileges"
    echo "Please run with: sudo $0"
    exit 1
fi

Real-World Script Examples

System Health Check Script

#!/bin/bash
# health_check.sh - Monitor system resources

check_disk() {
    local threshold=80
    local usage=$(df / | tail -1 | awk '{print $5}' | tr -d '%')

    if [ "$usage" -gt "$threshold" ]; then
        echo "WARNING: Disk usage is ${usage}% (threshold: ${threshold}%)"
        return 1
    fi
    echo "OK: Disk usage is ${usage}%"
    return 0
}

check_memory() {
    local threshold=80
    local usage=$(free | grep Mem | awk '{print int($3/$2 * 100)}')

    if [ "$usage" -gt "$threshold" ]; then
        echo "WARNING: Memory usage is ${usage}% (threshold: ${threshold}%)"
        return 1
    fi
    echo "OK: Memory usage is ${usage}%"
    return 0
}

check_load() {
    local threshold=4
    local load=$(uptime | awk -F'load average:' '{print $2}' | cut -d, -f1 | tr -d ' ')
    local load_int=${load%.*}

    if [ "$load_int" -gt "$threshold" ]; then
        echo "WARNING: Load average is $load (threshold: $threshold)"
        return 1
    fi
    echo "OK: Load average is $load"
    return 0
}

echo "=== System Health Check ==="
echo "Date: $(date)"
echo ""

check_disk
check_memory
check_load

echo ""
echo "=== Check Complete ==="

Log Rotation Script

#!/bin/bash
# rotate_logs.sh - Compress and archive old log files

LOG_DIR="/var/log/myapp"
ARCHIVE_DIR="/backup/logs"
DAYS_TO_KEEP=30

# Create archive directory if needed
mkdir -p "$ARCHIVE_DIR"

# Compress logs older than 1 day
find "$LOG_DIR" -name "*.log" -mtime +1 -exec gzip {} \;

# Move compressed logs to archive
find "$LOG_DIR" -name "*.log.gz" -exec mv {} "$ARCHIVE_DIR/" \;

# Delete archives older than retention period
find "$ARCHIVE_DIR" -name "*.log.gz" -mtime +$DAYS_TO_KEEP -delete

echo "Log rotation complete: $(date)"

Next Steps

Now that you understand the basics of writing scripts:

  1. Practice daily: Automate one small task each day
  2. Read others' scripts: Learn from open-source projects
  3. Learn a second language: If you know Bash, try Python; if you know PowerShell, try Bash
  4. Build a script library: Save and organize useful scripts for reuse
  5. Version control: Use Git to track changes to your scripts

Related Resources:

Conclusion

Learning how to write scripts is one of the most valuable skills you can develop in IT. Scripts save time, reduce errors, and enable you to automate repetitive tasks that would otherwise consume hours of manual work. Start with simple scripts that solve real problems you face daily, and gradually build complexity as your skills grow.

The key to becoming proficient at scripting is practice. Every system administrator, developer, and DevOps engineer started with their first "Hello World" script. Pick a language, solve a problem, and keep building. Before long, you'll wonder how you ever worked without automation.

Frequently Asked Questions

Find answers to common questions

Pick Python—it's the easiest scripting language to learn and the most useful for IT work. Install Python 3, open a text editor, and write your first script: a simple file that prints 'Hello World' and run it with python script.py. That's it. Once you've run your first script, move on to reading files, automating file operations, and working with APIs. Don't spend weeks on tutorials—learn by doing. Write a script that solves a real problem you have today, even if it's just renaming 100 files. You'll learn more from one real script than from 10 hours of video tutorials.

Use try/except blocks but keep them specific—catch the exact error you expect, not generic exceptions. For example, use except FileNotFoundError: instead of except Exception:. Always log errors with context: print what failed, what you were trying to do, and the actual error message. Add a timestamp. Bad error handling hides problems; good error handling tells you exactly what broke and where. For production scripts, write errors to a log file instead of just printing them—you need a record when things fail at 2 AM and you're not watching.

Use bash for simple file operations and command chaining (moving files, running programs in sequence). Use Python when you need logic, error handling, or API calls. If your script has more than 20 lines of bash or needs if/else logic beyond basic file checks, switch to Python. Bash is great for quick automation that just runs commands. Python is better for anything that needs to make decisions, handle errors gracefully, or work with data. Most IT automation ends up needing Python eventually, so starting there saves you from rewriting bash scripts later.

Three things: error handling, logging, and testing. Wrap operations in try/except blocks, log everything with timestamps, and test the script manually a few times before scheduling it. For critical scripts, add email alerts when errors occur—you can't fix what you don't know about. Test edge cases: what happens if the file doesn't exist? If the API is down? If you run it twice at the same time? A reliable script assumes everything will fail eventually and handles it gracefully instead of crashing silently.

Look for tasks you do daily that involve the same steps every time. Common first scripts: batch renaming files, backing up directories, pulling data from an API and saving it to Excel, sending automated email reports, or monitoring a folder for new files. Pick something you do at least once a week that takes 5+ minutes. Even if your script takes 2 hours to write, you'll save that time back within a month. The best first script is one that automates your most annoying repetitive task.

Transform Your IT with Automation

Streamline operations, reduce manual tasks, and improve security with intelligent automation.