Linux CLI 53 🐧 shell scripts introduction
nano myscript.sh
#!/bin/bash
# This is a comment
echo "Hello, World!"
# save and exit
chmod +x myscript.sh
./myscript.sh
A shell script is a plain-text file full of shell commands that the system runs for you, in order, automatically. Instead of typing the same sequence of commands over and over, you write them once and run the script. It’s the simplest form of programming on Linux — and one of the most useful.
Key point: A shell script is interpreted, not compiled. The shell reads it line by line and executes each command. No build step, no binary — just a text file with execute permission.
a – what is a shell script
A shell script is a sequence of commands written in a plain-text file that is executed by a Unix or Linux shell. This script automates the execution of tasks and can be used for a variety of purposes.
Purpose:
- Helps automate repetitive tasks, making them faster and less error-prone
- Turns a series of manual steps into a single command
- Captures knowledge — the script documents what needs to happen
Interpreted language:
- Interpreted by the shell (like
bash), not compiled - The shell reads the file and executes each command in turn
- If a command fails, the shell moves to the next line (unless you tell it not to)
Command-based:
- Consists of a series of commands that can be run manually in the terminal
- Anything you can type at the prompt, you can put in a script
- Pipes, redirects, variables, and globbing all work the same way
Extensibility:
- Can include control structures like loops, conditionals, and functions
- Can accept arguments and read user input
- Can call other programs, scripts, and system utilities
Portability:
- Can often be made portable across different Unix-like systems
- POSIX-compliant scripts run on
sh,bash,dash,ksh, andzsh - Bash-specific features limit portability to systems with bash
Common uses:
| Use case | Example |
|---|---|
| Automation | Backups, log rotation, cleanup |
| Deployment | Build, test, and release code |
| System administration | User management, monitoring |
| Batch processing | Convert files, resize images |
| Scheduled tasks | Cron jobs, systemd timers |
| Glue between tools | Chain commands into pipelines |
A minimal script:
#!/bin/bash
# This is a comment
echo "Hello, World!"
That’s it. Two lines — a shebang and a command. Save it, make it executable, run it.
What makes a script a script:
┌──────────────────────────────────────────────┐
│ Anatomy of a shell script │
│ │
│ #!/bin/bash ← shebang (interpreter)│
│ │
│ # Comments ← ignored by the shell│
│ │
│ VAR="value" ← variables │
│ echo "$VAR" ← commands │
│ │
│ if [ ... ]; then ← conditionals │
│ ... │ │
│ fi │ │
│ │ │
│ for i in ...; do ← loops │
│ ... │ │
│ done │ │
│ │ │
│ myfunc() { ← functions │
│ ... │ │
│ } │ │
│ │
│ exit 0 ← exit status │
│ │
└──────────────────────────────────────────────┘
b – How to write a shell script
Writing a shell script is a six-step process. Once you’ve done it a few times, it becomes second nature.
Step 1 — Open a text editor
Use any editor you’re comfortable with:
| Editor | Command |
|---|---|
| nano | nano myscript.sh |
| vim | vim myscript.sh |
| vi | vi myscript.sh |
| gedit | gedit myscript.sh |
| kate | kate myscript.sh |
The .sh extension is a convention, not a requirement — but it makes it clear the file is a shell script.
Step 2 — Add the shebang line
The shebang is the very first line of the script:
#!/bin/bash
It tells the system which interpreter to use. Without it, the script might be run by the wrong shell or fail entirely.
Common shebangs:
| Shebang | Interpreter |
|---|---|
#!/bin/bash | Bash |
#!/bin/sh | POSIX shell (often dash) |
#!/usr/bin/env bash | Bash, found via PATH |
#!/usr/bin/env python3 | Python 3 |
#!/usr/bin/env perl | Perl |
Tip:
#!/usr/bin/env bashis more portable than#!/bin/bashbecause it locates bash via your PATH rather than hardcoding its location.
Step 3 — Write your script
Add your commands, one per line. Here’s an example:
#!/bin/bash
# This is a comment
echo "Hello, World!"
# Use a variable
NAME="Kronos"
echo "Hello, $NAME!"
# Run a command
date
Step 4 — Save and exit
In nano, press Ctrl+O, then Enter, then Ctrl+X.
In vim, press Esc, then type :wq and press Enter.
Step 5 — Make the script executable
A script needs execute permission to be run directly:
chmod +x myscript.sh
Verify:
ls -l myscript.sh
-rwxr-xr-x 1 kronos kronos 123 Jan 15 10:00 myscript.sh
# ^^^ execute bits are set
Step 6 — Run the script
./myscript.sh
Hello, World!
Hello, Kronos!
Mon Jan 15 10:00:00 UTC 2024
The ./ is required — it tells the shell to look in the current directory. Without it, the shell searches your PATH and won’t find your script.
Alternative ways to run a script:
# Explicitly with bash (no execute permission needed)
$ bash myscript.sh
# With sh
$ sh myscript.sh
# As a command if it's in your PATH
$ mv myscript.sh ~/bin/
$ myscript.sh
In a shell script you can have:
| Feature | Example |
|---|---|
| Variables | NAME="Kronos" |
| Conditionals | if [ -f file ]; then ... fi |
| Loops | for i in 1 2 3; do ... done |
| Functions | myfunc() { echo "hi"; } |
| Arguments | $1, $2, $@ |
| User input | read -p "Name: " name |
| Command substitution | TODAY=$(date +%F) |
| Exit codes | exit 0 |
You can also take input from the user:
#!/bin/bash
read -p "What is your name? " name
echo "Hello, $name!"
$ ./greet.sh
What is your name? Kronos
Hello, Kronos!
A slightly bigger example:
#!/bin/bash
# backup.sh — back up a directory with a timestamp
SRC="$1"
DST="$2"
if [ -z "$SRC" ] || [ -z "$DST" ]; then
echo "Usage: $0 <source> <destination>"
exit 1
fi
if [ ! -d "$SRC" ]; then
echo "Error: $SRC is not a directory"
exit 1
fi
STAMP=$(date +%F-%H%M)
ARCHIVE="$DST/backup-$STAMP.tar.gz"
tar -czf "$ARCHIVE" "$SRC"
echo "Backup created: $ARCHIVE"
$ chmod +x backup.sh
$ ./backup.sh /home/kronos/docs /backup
Backup created: /backup/backup-2024-01-15-1000.tar.gz
Complete Example Session
# ============================================
# PART 1: CREATE THE SCRIPT
# ============================================
$ nano myscript.sh
In nano, type:
#!/bin/bash
# This is a comment
echo "Hello, World!"
Save with Ctrl+O, Enter, exit with Ctrl+X.
# ============================================
# PART 2: VERIFY THE FILE
# ============================================
$ cat myscript.sh
#!/bin/bash
# This is a comment
echo "Hello, World!"
$ ls -l myscript.sh
-rw-r--r-- 1 kronos kronos 52 Jan 15 10:00 myscript.sh
# Note: no execute permission yet
# ============================================
# PART 3: TRY TO RUN IT
# ============================================
$ ./myscript.sh
bash: ./myscript.sh: Permission denied
# ============================================
# PART 4: MAKE IT EXECUTABLE
# ============================================
$ chmod +x myscript.sh
$ ls -l myscript.sh
-rwxr-xr-x 1 kronos kronos 52 Jan 15 10:00 myscript.sh
# Execute bits are now set
# ============================================
# PART 5: RUN IT
# ============================================
$ ./myscript.sh
Hello, World!
# ============================================
# PART 6: RUN WITHOUT EXECUTE PERMISSION
# ============================================
$ chmod -x myscript.sh
$ bash myscript.sh
Hello, World!
# Works because bash reads the file
# ============================================
# PART 7: ADD VARIABLES AND COMMANDS
# ============================================
$ cat > greet.sh << 'EOF'
#!/bin/bash
# A script with a variable
NAME="Kronos"
echo "Hello, $NAME!"
echo "Today is $(date +%A)"
EOF
$ chmod +x greet.sh
$ ./greet.sh
Hello, Kronos!
Today is Monday
# ============================================
# PART 8: TAKE USER INPUT
# ============================================
$ cat > ask.sh << 'EOF'
#!/bin/bash
read -p "What is your name? " name
echo "Hello, $name!"
EOF
$ chmod +x ask.sh
$ ./ask.sh
What is your name? Alice
Hello, Alice!
# ============================================
# PART 9: USE COMMAND-LINE ARGUMENTS
# ============================================
$ cat > args.sh << 'EOF'
#!/bin/bash
echo "Script: $0"
echo "First arg: $1"
echo "Second arg: $2"
echo "All args: $@"
echo "Number of args: $#"
EOF
$ chmod +x args.sh
$ ./args.sh hello world
Script: ./args.sh
First arg: hello
Second arg: world
All args: hello world
Number of args: 2
# ============================================
# PART 10: CONDITIONALS AND LOOPS
# ============================================
$ cat > check.sh << 'EOF'
#!/bin/bash
if [ -f /etc/passwd ]; then
echo "/etc/passwd exists"
else
echo "/etc/passwd is missing!"
fi
for i in 1 2 3; do
echo "Number: $i"
done
EOF
$ chmod +x check.sh
$ ./check.sh
/etc/passwd exists
Number: 1
Number: 2
Number: 3
Quick Reference
Shebangs
| Shebang | Interpreter |
|---|---|
#!/bin/bash | Bash |
#!/bin/sh | POSIX shell |
#!/usr/bin/env bash | Bash via PATH |
#!/usr/bin/env python3 | Python 3 |
#!/usr/bin/env perl | Perl |
Creating a Script
| Step | Command |
|---|---|
| 1. Open editor | nano myscript.sh |
| 2. Add shebang | #!/bin/bash |
| 3. Write commands | echo "Hello" |
| 4. Save & exit | Ctrl+O, Enter, Ctrl+X |
| 5. Make executable | chmod +x myscript.sh |
| 6. Run | ./myscript.sh |
Running a Script
| Method | Command |
|---|---|
| Direct | ./myscript.sh |
| With bash | bash myscript.sh |
| With sh | sh myscript.sh |
| From PATH | myscript.sh (after mv to ~/bin) |
Script Features
| Feature | Syntax |
|---|---|
| Comment | # comment |
| Variable | VAR="value" |
| Use variable | $VAR or ${VAR} |
| Command substitution | $(command) |
| Argument | $1, $2, $@ |
| Argument count | $# |
| Script name | $0 |
| User input | read -p "Prompt: " var |
| Exit | exit 0 |
| Conditional | if [ ... ]; then ... fi |
| Loop | for i in ...; do ... done |
| Function | name() { ... } |
File Permissions
| Command | Effect |
|---|---|
chmod +x FILE | Add execute |
chmod -x FILE | Remove execute |
chmod 755 FILE | rwxr-xr-x |
chmod 700 FILE | rwx—— |
ls -l FILE | Check permissions |
Best Practices
✅ Do This:
# Always include a shebang
#!/bin/bash # ✅
# Comment your scripts
# This script backs up files # ✅
# Use meaningful variable names
BACKUP_DIR="/backup" # ✅
# Quote variables
echo "$NAME" # ✅
# Make scripts executable
chmod +x myscript.sh # ✅
# Check arguments
if [ -z "$1" ]; then
echo "Usage: $0 <arg>"
exit 1
fi # ✅
# Use exit codes
exit 0 # ✅
# Test with bash first
bash myscript.sh # ✅
❌ Don’t Do This:
# Don't forget the shebang
echo "Hello" # ❌ may fail
# Don't use unquoted variables with spaces
echo $NAME # ❌ if NAME has spaces
# Don't assume a specific directory
cd /tmp # ⚠️ use absolute paths
# Don't ignore errors silently
rm -rf $DIR/* # ❌ dangerous if DIR empty
# Don't use tabs and spaces inconsistently
if [ ... ]; then
echo "x" # ⚠️ use consistent indent
# Don't name your script after an existing command
ls.sh # ⚠️ confusing
# Don't hardcode paths that may change
/usr/local/bin/myapp # ⚠️ use $PATH lookup
Common Pitfalls
| Pitfall | Problem | Solution |
|---|---|---|
| No shebang | Wrong interpreter | Add #!/bin/bash |
| No execute bit | Permission denied | chmod +x |
Running without ./ | Command not found | Use ./script.sh |
| Unquoted variables | Word splitting | Use "$VAR" |
| CRLF line endings | bad interpreter error | dos2unix script.sh |
Spaces around = | Variable not set | VAR=value (no spaces) |
| Relative paths | Fails from other dirs | Use absolute paths |
| Not checking args | Crashes on missing input | Validate $1, $2 |
Real-World Examples
1. Hello World
#!/bin/bash
echo "Hello, World!"
2. Greet the User
#!/bin/bash
read -p "What is your name? " name
echo "Hello, $name!"
3. Show the Date
#!/bin/bash
echo "Today is $(date +%A), $(date +%F)"
4. List Files with Details
#!/bin/bash
ls -lh "$1"
5. Check if a File Exists
#!/bin/bash
if [ -f "$1" ]; then
echo "$1 exists"
else
echo "$1 not found"
exit 1
fi
6. Loop Over Arguments
#!/bin/bash
for arg in "$@"; do
echo "Argument: $arg"
done
7. Simple Backup Script
#!/bin/bash
SRC="$1"
DST="$2"
STAMP=$(date +%F-%H%M)
tar -czf "$DST/backup-$STAMP.tar.gz" "$SRC"
echo "Backup saved to $DST/backup-$STAMP.tar.gz"
8. Disk Usage Warning
#!/bin/bash
THRESHOLD=80
USAGE=$(df / | awk 'NR==2 {print $5}' | tr -d '%')
if [ "$USAGE" -gt "$THRESHOLD" ]; then
echo "Warning: disk usage is ${USAGE}%"
fi
9. Rename All .txt Files
#!/bin/bash
for f in *.txt; do
mv "$f" "${f%.txt}.md"
done
10. Count Lines in Files
#!/bin/bash
for f in "$@"; do
printf "%5d %s\n" "$(wc -l < "$f")" "$f"
done
11. Check If a Service Is Running
#!/bin/bash
SERVICE="sshd"
if systemctl is-active --quiet "$SERVICE"; then
echo "$SERVICE is running"
else
echo "$SERVICE is not running"
fi
12. Simple Menu
#!/bin/bash
echo "1) Show date"
echo "2) Show uptime"
echo "3) Quit"
read -p "Choice: " choice
case "$choice" in
1) date ;;
2) uptime ;;
3) exit 0 ;;
*) echo "Invalid choice" ;;
esac
13. Log Rotation
#!/bin/bash
LOG="/var/log/myapp.log"
if [ -f "$LOG" ]; then
mv "$LOG" "$LOG.$(date +%F)"
touch "$LOG"
echo "Log rotated"
fi
14. Deploy Script
#!/bin/bash
set -e # exit on error
git pull
npm install
npm run build
sudo systemctl restart myapp
echo "Deployed successfully"
15. Generate a Report
#!/bin/bash
echo "=== System Report ==="
echo "Date: $(date)"
echo "Host: $(hostname)"
echo "Uptime: $(uptime -p)"
echo "Disk:"
df -h /
echo "Memory:"
free -h
Visual: Script Execution
┌──────────────────────────────────────────────┐
│ How a script runs │
│ │
│ $ ./myscript.sh │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────┐ │
│ │ Kernel reads the shebang │ │
│ │ #!/bin/bash │ │
│ │ → launches /bin/bash │ │
│ └────────────┬───────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────┐ │
│ │ Bash reads the script line by line │ │
│ │ │ │
│ │ # comment ← ignored │ │
│ │ echo "Hello" ← executed │ │
│ │ date ← executed │ │
│ │ exit 0 ← returns 0 │ │
│ └────────────┬───────────────────────────┘ │
│ │ │
│ ▼ │
│ Output to terminal │
│ │
└──────────────────────────────────────────────┘
Summary
| Concept | Meaning |
|---|---|
| Shell script | Text file of shell commands |
| Shebang | #!/bin/bash — picks the interpreter |
| Execute bit | Needed to run ./script.sh |
| Variable | VAR="value" |
| Use variable | $VAR or ${VAR} |
| Argument | $1, $2, $@ |
| User input | read -p "Prompt: " var |
| Conditional | if [ ... ]; then ... fi |
| Loop | for i in ...; do ... done |
| Function | name() { ... } |
| Exit code | exit 0 (success) |
Key takeaways:
- A shell script is a plain-text file of commands executed by the shell
- It’s interpreted, not compiled — no build step
- The shebang (
#!/bin/bash) must be the first line — it picks the interpreter - Six steps to write one: open, shebang, write, save, chmod +x, run
- Run with
./script.sh— the./tells the shell to look in the current directory - Scripts can have variables, conditionals, loops, functions, arguments, and user input
- Use
chmod +xto make a script executable - Use
bash script.shif you don’t want to set the execute bit - Quote your variables —
"$VAR", not$VAR - Scripts are for automation, deployment, system administration, and batch processing
Remember: A shell script is just commands in a file. Start with #!/bin/bash, add echo "Hello, World!", save, chmod +x, and run ./myscript.sh. From there, add variables, arguments, conditionals, and loops as you need them. Scripts are the fastest way to automate anything you do more than once. Learn to write them, and you’ll never type the same sequence of commands twice.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!