Skip to content

Shell Scripting for Developer Productivity

DodaTech Updated 2026-06-22 6 min read

In this tutorial, you'll learn shell scripting including variables, conditionals, loops, functions, error handling, and writing utility scripts that automate repetitive development tasks.

Why Shell Scripting Matters

Every developer faces repetitive tasks: renaming files, deploying code, backing up databases, processing logs, or setting up projects. Shell scripting turns these into one-command operations. A well-written Shell Script saves minutes every day and hours every week. Unlike higher-level languages, shell scripting gives you direct access to the operating system, pipelines, and all command-line tools.

By the end of this guide, you will write robust shell scripts that handle errors, accept arguments, and automate real development workflows.

What is Shell Scripting?

A Shell Script is a file containing a sequence of commands for a Unix shell (Bash, Zsh, etc.). Scripts automate multi-step tasks that would otherwise require manual command entry.

flowchart LR
  A[Shell Script] --> B[Variables]
  A --> C[Conditionals]
  A --> D[Loops]
  A --> E[Functions]
  B --> F[User Input]
  B --> G[Command Output]
  C --> H[if/else]
  C --> I[case]
  D --> J[for]
  D --> K[while]
  E --> L[Reusable Code Blocks]

Your First Script

#!/bin/bash
# hello.sh — A simple greeting script

echo "Hello, World!"

Making It Executable

chmod +x hello.sh
./hello.sh

Expected Output

Hello, World!

Variables

#!/bin/bash

# Defining variables (no spaces around =)
name="Alice"
greeting="Hello"

# Using variables with $
echo "$greeting, $name!"

# Command substitution
current_date=$(date)
echo "Today is: $current_date"

# Arithmetic
count=$((5 + 3))
echo "Count: $count"

Expected Output

Hello, Alice!
Today is: Mon Jun 22 09:15:00 UTC 2026
Count: 8

Variable Best Practices

# Use uppercase for environment variables
export PROJECT_DIR="$HOME/projects/myapp"

# Use quotes to handle spaces
filename="my file.txt"
cat "$filename"  # Correct
cat $filename    # Wrong — splits on space

# Default values
echo "${name:-World}"  # Uses "World" if $name is unset

# Read-only variables
readonly VERSION="1.0.0"

Conditionals

#!/bin/bash

# if/elif/else
file="test.txt"

if [ -f "$file" ]; then
  echo "$file exists"
elif [ -d "$file" ]; then
  echo "$file is a directory"
else
  echo "$file does not exist"
fi

# Numeric comparison
count=42
if [ "$count" -gt 10 ]; then
  echo "Count is greater than 10"
fi

# String comparison
name="Alice"
if [ "$name" = "Alice" ]; then
  echo "Hello, Alice!"
fi

File Test Operators

Operator True if
-f File exists and is a regular file
-d Directory exists
-e File exists (any type)
-r File is readable
-w File is writable
-x File is executable
-s File exists and is not empty

Loops

For Loop

#!/bin/bash

# Loop over files
for file in *.txt; do
  echo "Processing $file"
  wc -l "$file"
done

# Loop over a range
for i in {1..5}; do
  echo "Iteration $i"
done

# Loop over command output
for user in $(cat /etc/passwd | cut -d: -f1); do
  echo "User: $user"
done

While Loop

#!/bin/bash

# Read file line by line
while IFS= read -r line; do
  echo "Line: $line"
done < input.txt

# Countdown
count=5
while [ "$count" -gt 0 ]; do
  echo "$count..."
  count=$((count - 1))
  sleep 1
done
echo "Go!"

Functions

#!/bin/bash

# Define a function
greet() {
  local name="$1"
  echo "Hello, $name!"
}

# Function with return value
is_even() {
  local num=$1
  if [ $((num % 2)) -eq 0 ]; then
    return 0  # Success
  else
    return 1  # Failure
  fi
}

# Call functions
greet "Alice"

if is_even 42; then
  echo "42 is even"
fi

Error Handling

#!/bin/bash
set -e  # Exit on any error
set -u  # Exit on undefined variable
set -o pipefail  # Fail if any command in a pipe fails

# Or combine: set -euo pipefail

# Manual error checking
if ! mkdir -p "$OUTPUT_DIR"; then
  echo "Error: Could not create directory $OUTPUT_DIR" >&2
  exit 1
fi

# Trap errors
cleanup() {
  echo "Cleaning up..."
  rm -rf "$TEMP_DIR"
}
trap cleanup EXIT

TEMP_DIR=$(mktemp -d)
# ... do work ...
# cleanup runs automatically on exit

Argument Parsing

#!/bin/bash

usage() {
  echo "Usage: $0 -n <name> -o <output> [-v]"
  echo "  -n    Name (required)"
  echo "  -o    Output directory (required)"
  echo "  -v    Verbose mode"
  exit 1
}

verbose=false

while getopts "n:o:v" opt; do
  case $opt in
    n) name="$OPTARG" ;;
    o) output="$OPTARG" ;;
    v) verbose=true ;;
    *) usage ;;
  esac
done

if [ -z "${name:-}" ] || [ -z "${output:-}" ]; then
  usage
fi

if [ "$verbose" = true ]; then
  echo "Name: $name"
  echo "Output: $output"
fi

Real-World Script: Project Scaffolder

#!/bin/bash
# scaffold.sh — Create a new project structure

set -euo pipefail

PROJECT_NAME="${1:-my-project}"
PROJECT_DIR="$HOME/projects/$PROJECT_NAME"

create_project() {
  local name="$1"
  local dir="$2"

  echo "Creating project: $name"

  # Create directory structure
  mkdir -p "$dir"/{src,test,docs,scripts}
  mkdir -p "$dir/src"/{components,utils,styles}

  # Create files
  cat > "$dir/README.md" << EOF
# $name

Project description here.
EOF

  cat > "$dir/.gitignore" << EOF
node_modules/
dist/
.env
*.log
EOF

  cat > "$dir/package.json" << EOF
{
  "name": "$name",
  "version": "1.0.0",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "test": "vitest"
  }
}
EOF

  # Initialize git
  cd "$dir"
  git init
  git add .
  git commit -m "Initial commit: scaffold $name"

  echo "Project created at: $dir"
}

if [ -d "$PROJECT_DIR" ]; then
  echo "Error: Directory $PROJECT_DIR already exists" >&2
  exit 1
fi

create_project "$PROJECT_NAME" "$PROJECT_DIR"

Debugging Scripts

# Dry run (show commands without executing)
bash -n script.sh

# Trace execution
bash -x script.sh

# Debug sections in the script
set -x  # Start debugging
# ... code to debug ...
set +x  # Stop debugging

Common Errors

Problem Cause Fix
command not found Script not in PATH or not executable Use ./script.sh or add to PATH
[: too many arguments Unquoted variable with spaces Always quote variables: [ "$var" = "value" ]
syntax error: unexpected end of file Missing closing fi, done, or esac Check block terminator matching
Permission denied File not executable chmod +x script.sh
Line endings cause errors on Linux Windows line endings (\r\n) Use dos2unix script.sh or set editor to LF

Practice Questions

1. What is the shebang line and why is it used?

#!/bin/bash at the top tells the system which Interpreter to use.

2. How do you capture the output of a command into a variable?

variable=$(command).

3. What does set -euo pipefail do?

Exits on error, undefined variables, and any pipe failure.

4. How do you define a function in bash?

function_name() { ... } and call it as function_name.

5. What is the difference between > and >> in redirection?

> overwrites the file. >> appends to the file.

Challenge

Write a Shell Script called backup.sh that creates a timestamped backup of a specified directory, compresses it with gzip, stores backups in a ~/backups/ directory, keeps only the last 7 backups (deletes older ones), and logs all operations to a log file. Include error handling for missing directories and disk space issues.

Real-World Task

Write a Shell Script that automates your daily development setup. The script should: pull the latest changes from Git for a project, install any new dependencies, run database migrations, and start the development server. Make it accept an optional project name argument. Add verbose and help flags.

Should I use Bash or Python for scripting?

Use Bash for file operations, pipelines, and when working closely with the OS. Use Python for complex logic, data processing, or cross-platform scripts.

How do I debug a shell script?

Run with bash -x script.sh to trace execution. Add set -x and set +x around sections you want to debug.

What does `2>&1` mean?

It redirects stderr (file descriptor 2) to stdout (file descriptor 1), merging error output with normal output.

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro