Introduction
There's a moment every developer eventually hits — you find yourself doing the same repetitive task for the tenth time that week. Maybe it's renaming a batch of files, SSHing into servers and running the same commands, or cleaning up log directories. You do it manually, again, and somewhere in the back of your head a little voice says: "There has to be a better way."
That better way is shell scripting.
Shell scripting is one of those foundational skills that quietly separates developers who feel comfortable on a Linux system from those who feel like they're just guessing. It's not glamorous. It won't land you on the front page of Hacker News. But the ability to write a script that saves you 20 minutes every day? Over a year, that's more than 120 hours back in your pocket.
For DevOps engineers and sysadmins, scripting isn't optional — it's oxygen. Deployments, backups, health checks, log rotation, user provisioning — all of it gets automated with shell scripts. But even if you're a backend developer or just getting started with Linux, learning to write basic scripts will make your day-to-day dramatically more efficient.
This guide is Part 1 of a two-part series. We're going to go from "what even is a shell?" to writing a working script that takes arguments, reads user input, and does real arithmetic — all from scratch. No experience needed.
Let's get into it.
What is a Shell Script?
Before we write anything, let's get the vocabulary straight.
The Shell
When you open a terminal on Linux or macOS, you're not talking directly to the operating system kernel. There's a program sitting in between — that's the shell. It reads the commands you type, interprets them, and tells the OS what to do.
Think of it like a translator. You speak "human command language," the shell translates it, and the OS executes it.
Bash
There are several shell programs out there — sh, zsh, fish, dash — but the one you'll encounter most in the wild, especially on Linux servers, is Bash (Bourne Again SHell). It's been around since 1989, it's installed on virtually every Linux system, and it's what most shell scripting tutorials (including this one) use.
When you open a terminal and start typing commands, there's a very good chance you're already using Bash.
# Check which shell you're currently using
echo $SHELL
# Check your bash version
bash --version
What is a Shell Script?
A shell script is just a plain text file that contains a series of commands — the same commands you'd type in a terminal, but saved in a file so they can be run all at once, on demand, automatically.
That's it. There's no compiling, no special runtime. It's text that the shell reads and executes line by line.
Why is Scripting So Powerful?
- Repeatability — Run the exact same sequence of commands every time, with no typos or forgotten steps.
- Automation — Schedule scripts to run at 3am without you being there.
- Speed — What takes you 10 manual commands takes a script half a second.
- Portability — A script that works on one Linux server will usually work on another.
Creating Your First Script
Time to write something. Open your terminal and follow along.
Step 1: Create the Script File
A shell script is just a file. By convention, shell script files end with .sh, though technically the extension doesn't matter to the shell.
# Create a new file called hello.sh
touch hello.sh
# Open it in a text editor
nano hello.sh
Add the following content:
#!/bin/bash
echo "Hello, World!"
echo "My first shell script is running."
Save and exit (Ctrl+O, then Ctrl+X in nano).
Step 2: Make It Executable
By default, a new file doesn't have execute permission. If you try to run it as-is, you'll get a "Permission denied" error. You need to tell Linux that this file is allowed to be executed:
chmod +x hello.sh
chmod stands for change mode. The +x adds execute permission for the file owner. You only have to do this once per script.
Tip: Run
ls -l hello.shbefore and afterchmod +xto see the permissions change. You'll notice anxappear in the permission string.
Step 3: Run the Script
Now you can execute it:
./hello.sh
You should see:
Hello, World!
My first shell script is running.
The ./ prefix tells the shell to look for the file in the current directory. Without it, the shell would only look in directories listed in your $PATH environment variable.
Alternative: You can also run it as
bash hello.sh— this works even withoutchmod +x. But using./with execute permissions is the standard practice.
Understanding the Shebang
You probably noticed the first line of the script:
#!/bin/bash
This is called the shebang (also written as "hashbang"). It's not a comment, even though it starts with #. It's a special directive for the operating system.
How It Works
When you execute a file, the OS looks at the very first two characters. If it sees #!, it knows: "This is a script — the path that follows tells me which interpreter to use."
So #!/bin/bash is saying: "Use the program located at /bin/bash to execute this script."
If you were writing a Python script instead, you might use:
#!/usr/bin/env python3
Or for a Node.js script:
#!/usr/bin/env node
Always Include It
Some scripts will run without a shebang, but the behavior depends on whatever shell happens to be running them — which can vary between systems. Always include #!/bin/bash at the top of your Bash scripts. It makes your script's behavior explicit and predictable.
#!/bin/bash
# Your script starts here
echo "Shebang ensures I always run with Bash"
Tip: Use
which bashto find the exact path to Bash on your system. On most systems it's/bin/bash, but on some (like certain macOS setups with Homebrew) it might be/usr/local/bin/bash. Using#!/usr/bin/env bashis a more portable alternative that searches your$PATHfor bash.
Variables in Shell Scripts
Variables let you store values and reuse them. In Bash, they're simple to declare — maybe a little too simple, because the syntax is strict and easy to get wrong at first.
Declaring a Variable
#!/bin/bash
name="Malhar"
age=21
city="Vadodara"
Rules to live by:
- No spaces around the
=sign.name = "Malhar"will fail. It must bename="Malhar". - Variable names are case-sensitive.
Nameandnameare different variables. - By convention, use lowercase for regular script variables and UPPERCASE for environment variables and constants.
Using a Variable
To use (or "reference") a variable, prefix its name with $:
#!/bin/bash
name="Malhar"
city="Vadodara"
echo "Hello, my name is $name and I live in $city."
Output:
Hello, my name is Malhar and I live in Vadodara.
Curly Brace Syntax
When a variable name could be ambiguous — like when you're placing it right next to other text — wrap it in curly braces:
#!/bin/bash
animal="dog"
echo "I have one ${animal}."
echo "I have two ${animal}s." # Without braces, $animals would fail
Output:
I have one dog.
I have two dogs.
Tip: Get in the habit of using
${variable}over$variable— it prevents subtle bugs and makes your scripts easier to read.
Storing Command Output in a Variable
This is a technique you'll use constantly — capturing the output of a command into a variable:
#!/bin/bash
current_date=$(date)
current_user=$(whoami)
echo "Script run by: $current_user"
echo "Date: $current_date"
The $(...) syntax runs the command inside and captures its output. This is called command substitution.
Command Line Arguments
Scripts become far more useful when they can accept input at the time you run them — without needing to edit the file.
How Arguments Work
When you run a script like this:
./greet.sh Alice DevOps
Bash automatically populates special variables:
| Variable | Value | Description |
|---|---|---|
$0 |
./greet.sh |
The name of the script itself |
$1 |
Alice |
First argument |
$2 |
DevOps |
Second argument |
$3 |
(empty) | Third argument (not provided here) |
$# |
2 |
Total number of arguments passed |
$@ |
Alice DevOps |
All arguments as a list |
Example Script
Create a file called greet.sh:
#!/bin/bash
echo "Script name: $0"
echo "Hello, $1! You work in $2."
echo "Total arguments passed: $#"
Make it executable and run it:
chmod +x greet.sh
./greet.sh Alice DevOps
Output:
Script name: ./greet.sh
Hello, Alice! You work in DevOps.
Total arguments passed: 2
What if an Argument Isn't Provided?
If $1 is empty because no argument was given, your script might behave unexpectedly. A good practice (which we'll cover more in Part 2 with conditionals) is to provide a default:
#!/bin/bash
name=${1:-"stranger"} # Use $1 if provided, otherwise default to "stranger"
echo "Hello, $name!"
./greet.sh # → Hello, stranger!
./greet.sh Malhar # → Hello, Malhar!
Tip:
${variable:-default}is a Bash parameter expansion trick. The:-means "use this default value if the variable is unset or empty." Keep this one handy.
Taking Input from the User
Sometimes you want the script to pause and ask the user something while it's running. That's what the read command is for.
Basic read
#!/bin/bash
echo "What is your name?"
read user_name
echo "Nice to meet you, $user_name!"
The script will wait after printing the question. When the user types something and hits Enter, whatever they typed gets stored in user_name.
read -p (Prompt on the Same Line)
The -p flag lets you combine the prompt and the input on the same line, which looks cleaner:
#!/bin/bash
read -p "Enter your name: " user_name
read -p "Enter your city: " user_city
echo ""
echo "Welcome, $user_name from $user_city!"
Output (with user input in italics):
Enter your name: Malhar
Enter your city: Vadodara
Welcome, Malhar from Vadodara!
read -s (Silent Input)
For sensitive input like passwords, use -s to hide what the user types:
#!/bin/bash
read -sp "Enter your password: " user_pass
echo ""
echo "Password received (not printing it, obviously)."
Arithmetic Operations in Bash
Bash handles arithmetic a bit differently than most programming languages. The most reliable and readable way to do arithmetic is with the $(( )) syntax.
Basic Operations
#!/bin/bash
a=10
b=3
echo "Addition: $((a + b))"
echo "Subtraction: $((a - b))"
echo "Multiplication: $((a * b))"
echo "Division: $((a / b))" # Integer division only
echo "Modulo: $((a % b))"
echo "Exponentiation: $((a ** b))"
Output:
Addition: 13
Subtraction: 7
Multiplication: 30
Division: 3
Modulo: 1
Exponentiation: 1000
Important: Bash only does integer arithmetic by default.
$((10 / 3))gives you3, not3.333. If you need decimal math, usebcorawk— we'll touch on those in later parts of this series.
Storing Arithmetic Results
#!/bin/bash
width=8
height=5
area=$((width * height))
perimeter=$(( 2 * (width + height) ))
echo "Width: $width, Height: $height"
echo "Area: $area"
echo "Perimeter: $perimeter"
Output:
Width: 8, Height: 5
Area: 40
Perimeter: 26
Increment and Decrement
#!/bin/bash
count=0
((count++)) # Increment by 1
echo $count # 1
((count += 5)) # Add 5
echo $count # 6
((count--)) # Decrement by 1
echo $count # 5
Putting It All Together: A Small Practical Script
Let's combine everything we've covered — variables, arguments, user input, and arithmetic — into one cohesive script.
Scenario: You're building a simple tool for a gym management system. It takes a member's name and monthly fee as arguments, asks how many months they're signing up for, and calculates the total cost.
Create a file called gym_membership.sh:
#!/bin/bash
# ─────────────────────────────────────────
# gym_membership.sh
# Usage: ./gym_membership.sh <name> <monthly_fee>
# ─────────────────────────────────────────
# Grab arguments
member_name=${1:-"Member"}
monthly_fee=${2:-0}
echo "========================================="
echo " Gym Membership Calculator"
echo "========================================="
echo ""
echo "Welcome, $member_name!"
echo "Monthly fee: ₹${monthly_fee}"
echo ""
# Ask for duration
read -p "How many months are you signing up for? " months
# Calculate totals
total=$((monthly_fee * months))
annual_equivalent=$((monthly_fee * 12))
echo ""
echo "-----------------------------------------"
echo " Membership Summary"
echo "-----------------------------------------"
echo " Name: $member_name"
echo " Monthly Fee: ₹${monthly_fee}"
echo " Duration: ${months} months"
echo " Total Cost: ₹${total}"
echo " (Annual would be: ₹${annual_equivalent})"
echo "-----------------------------------------"
echo ""
echo "Registration complete. See you at the gym!"
Make it executable and run it:
chmod +x gym_membership.sh
./gym_membership.sh Malhar 999
Sample output:
=========================================
Gym Membership Calculator
=========================================
Welcome, Malhar!
Monthly fee: ₹999
How many months are you signing up for? 6
-----------------------------------------
Membership Summary
-----------------------------------------
Name: Malhar
Monthly Fee: ₹999
Duration: 6 months
Total Cost: ₹5994
(Annual would be: ₹11988)
-----------------------------------------
Registration complete. See you at the gym!
This is a real, working script. Not a toy. You could drop this into a server right now and use it.
Conclusion
Let's recap what you've learned in Part 1:
- What a shell script is — a plain text file with commands that the shell executes line by line
-
The shebang (
#!/bin/bash) — tells the OS which interpreter to use -
Creating and running scripts —
touch,chmod +x, and./script.sh -
Variables — declaring with
name="value", referencing with$nameor${name} -
Command line arguments —
$0,$1,$2,$#, and default values with${1:-default} -
User input —
read,read -p, andread -s -
Arithmetic —
$(( ))for clean integer math
These are the building blocks. Every shell script you'll ever write — no matter how complex — is made up of some combination of these fundamentals.
What's Coming in Part 2
We've only just scratched the surface. In Part 2, we're going to add the real logic that turns scripts from simple command sequences into actual automation tools:
-
Conditional logic —
if,elif,elseto make decisions -
Loops —
forandwhileto repeat actions - Case statements — cleaner multi-branch logic
- Functions — reusable blocks of code
- Exit codes — how scripts communicate success or failure
- Real automation scripts — backing up directories, monitoring disk usage, batch processing files
By the end of Part 2, you'll have scripts worth actually putting into a cron job.
Found this helpful? Drop a like or a comment — it genuinely helps. And if you're following along and something isn't working the way you expect, ask in the comments. Shell scripting has some gotchas that trip everyone up the first time.
See you in Part 2.
Top comments (0)