Getting Started with Shell Scripting: Your First Script
Writing your first shell script is simpler than you might think. In this guide, you'll learn how to create a script from scratch, understand the shebang line, make your file executable, and run it using different methods. By the end, you'll have a solid foundation to start automating tasks on any Unix-based system.
Your First Script
Every shell script is just a text file containing commands that your shell interpreter can execute. Let's start with the classic "Hello, World!" example to understand the basics.
Step 1: Create the Script File
Open your terminal and create a new file called hello.sh:
1touch hello.sh
Open it in your favorite text editor (nano, vim, VS Code, etc.) and add the following content:
1#!/bin/bash 2 3# This is a comment — the shell ignores anything after the # symbol 4echo "Hello, World!" 5echo "Today is $(date)" 6echo "Current user: $(whoami)" 7echo "Working directory: $(pwd)"
Step 2: Make It Executable
Before you can run the script directly, you need to give it execute permissions using the chmod command:
1chmod +x hello.sh
The +x flag adds execute permission for the owner, group, and others. You can verify the permissions with:
1ls -l hello.sh
Expected output:
-rwxr-xr-x 1 user group 123 Aug 16 10:00 hello.sh
Notice the x characters in the permission string — that's what allows the file to be run as a program.
Step 3: Run the Script
Now execute your script:
1./hello.sh
Output:
Hello, World!
Today is Sun Aug 16 10:00:00 UTC 2026
Current user: ubuntu
Working directory: /home/ubuntu/projects
Why
./? The./tells the shell to look for the script in the current directory. Without it, the shell searches only in directories listed in yourPATHenvironment variable.
The Shebang (#!)
The very first line of your script — #!/bin/bash — is called the shebang (or hashbang). It's not optional if you want your script to run reliably.
What Does the Shebang Do?
When you run a script as ./script.sh, the operating system looks at the first two characters (#!). It then uses the path that follows to determine which interpreter should execute the rest of the file.
Think of it as saying: "Hey system, don't guess — use this specific program to run me."
Common Shebang Lines
| Shebang | Interpreter | Use Case |
|---|---|---|
#!/bin/bash | Bash shell | Default for most Linux systems |
#!/bin/sh | POSIX shell | Maximum portability across Unix systems |
#!/usr/bin/env bash | Bash (via env) | Finds bash anywhere in the system PATH |
#!/usr/bin/env python3 | Python 3 | For Python scripts |
The Portable Shebang Pattern
For maximum compatibility, many developers prefer this pattern:
1#!/usr/bin/env bash
Why? Because bash might not always live at /bin/bash. On some systems (like certain BSD variants or macOS with Homebrew), it could be at /usr/local/bin/bash. The env utility searches the user's PATH to find the interpreter, making your script more portable.
Example: A Script with a Proper Shebang
1#!/usr/bin/env bash 2 3# Author: Tech3Space 4# Description: A simple system info script 5 6echo "=== System Information ===" 7echo "Hostname: $(hostname)" 8echo "OS: $(uname -o)" 9echo "Kernel: $(uname -r)" 10echo "Uptime: $(uptime -p)" 11echo "Shell: $SHELL" 12echo "Bash Version: $BASH_VERSION"
Save it as sysinfo.sh, make it executable, and run it:
1chmod +x sysinfo.sh 2./sysinfo.sh
Script Execution Methods
There are several ways to run a shell script, and each behaves slightly differently. Understanding these methods helps you choose the right one for your workflow.
Method 1: Direct Execution (Recommended)
1./script.sh
What happens:
- The shebang line determines the interpreter.
- A new subshell process is spawned to run the script.
- The script runs in isolation from your current shell session.
When to use it: This is the standard way to run scripts. Always use this for production scripts.
Method 2: Using the Bash Interpreter Explicitly
1bash script.sh
What happens:
- You explicitly tell the system to use
bashto interpret the file. - The shebang line is ignored.
- A new subshell is created.
When to use it: Useful for testing scripts quickly or when the script doesn't have execute permissions yet. Also helpful if you want to force a specific shell version:
1bash -x script.sh # Run with debug mode (prints each command before execution) 2bash -n script.sh # Syntax check only (doesn't execute)
Method 3: Using sh
1sh script.sh
What happens:
- Runs the script with the POSIX
shshell, not Bash. - Bash-specific features (arrays,
[[ ]],sourcevs.) may fail or behave differently.
When to use it: Testing for POSIX compliance or running on systems where only sh is available.
Method 4: Sourcing the Script
1source script.sh 2# OR 3. script.sh
What happens:
- The script runs in your current shell session — no new process is created.
- Any variables, functions, or environment changes made by the script persist after it finishes.
Example: Why Sourcing Matters
Create a script called setenv.sh:
1#!/bin/bash 2export MY_APP_ENV="production" 3export API_KEY="sk-123456789" 4echo "Environment variables set!"
Now compare the two methods:
1# Method A: Direct execution 2./setenv.sh 3echo $MY_APP_ENV # Output: (empty — variables were lost in the subshell) 4 5# Method B: Sourcing 6source setenv.sh 7echo $MY_APP_ENV # Output: production 8echo $API_KEY # Output: sk-123456789
When to use it: Loading environment variables, applying shell configuration changes, or defining functions you want available in your current terminal session.
Quick Comparison Table
| Method | Syntax | New Process? | Shebang Used? | Variables Persist? |
|---|---|---|---|---|
| Direct | ./script.sh | Yes | Yes | No |
| Bash | bash script.sh | Yes | No | No |
| Sh | sh script.sh | Yes | No | No |
| Source | source script.sh | No | No | Yes |
| Dot | . script.sh | No | No | Yes |
Practical Exercise: Build a Script Step by Step
Let's put everything together by creating a script that checks if a website is online.
Step 1: Create the File
1nano check_site.sh
Step 2: Write the Script
1#!/usr/bin/env bash 2 3# check_site.sh — Check if a website is reachable 4# Usage: ./check_site.sh example.com 5 6# Check if user provided a URL 7if [ -z "$1" ]; then 8 echo "Error: Please provide a website URL." 9 echo "Usage: $0 <domain>" 10 exit 1 11fi 12 13DOMAIN=$1 14echo "Checking connectivity to $DOMAIN..." 15 16# Use curl to check HTTP status 17HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "https://$DOMAIN") 18 19if [ "$HTTP_CODE" -eq 200 ]; then 20 echo "✅ $DOMAIN is online! (HTTP $HTTP_CODE)" 21 exit 0 22else 23 echo "⚠️ $DOMAIN returned HTTP $HTTP_CODE" 24 exit 1 25fi
Step 3: Test It
1chmod +x check_site.sh 2./check_site.sh google.com 3./check_site.sh nonexistent-domain-12345.com
Common Beginner Mistakes to Avoid
1. Forgetting the Shebang
Without a shebang, the system might use your current shell to run the script. If you're in zsh but wrote Bash-specific syntax, the script will fail.
2. Missing Execute Permission
1./script.sh 2# bash: ./script.sh: Permission denied
Always run chmod +x before trying to execute directly.
3. Windows Line Endings (CRLF)
If you edit scripts on Windows, they may have \r\n line endings instead of Unix \n. This causes:
bash: ./script.sh: /bin/bash^M: bad interpreter: No such file or directory
Fix it with:
1sed -i 's/\r$//' script.sh
4. Spaces Around = in Variable Assignment
1# Wrong — spaces cause a "command not found" error 2NAME = "Tech3Space" 3 4# Correct 5NAME="Tech3Space"
5. Forgetting to Quote Variables
1# Dangerous if filename contains spaces 2rm $filename 3 4# Safe 5rm "$filename"
Summary Checklist
Before running any script, verify:
- The shebang line (
#!/bin/bashor#!/usr/bin/env bash) is at the top - The file has execute permission (
chmod +x script.sh) - You're using the right execution method for your use case
- Variables are properly quoted
- You've tested on a non-production system first
What's Next?
Now that you can write and run basic scripts, the next step is learning about variables, data types, and user input. These building blocks let you create dynamic scripts that respond to different conditions and inputs.
Stay tuned for the next chapter in our Shell Scripting series!
Found this helpful? Share it with your team and save it for your next scripting project.