Guide

Your First Bash Script

Part 8 of 9By Amith Kumar7 min read
Part 8 of 9Storage, Text and Your First Scripts: A Hands-On Guide
  1. 1Disks and Partitions
  2. 2Filesystems, Mounts and fstab
  3. 3Disk Usage: df and du
  4. 4tar and Compression
  5. 5Text Processing With sed
  6. 6Text Processing With awk
  7. 7cut, sort, uniq and tr
  8. 8Your First Bash Script
  9. 9Scheduling an Automated Backup
Verified 19 Jul 2026 · Ubuntu 24.04 LTS

A bash script tutorial from a blank file

A bash script is a file of commands the shell runs in order, and this tutorial builds one from scratch. You will add a shebang, a variable, and a condition, make the file executable, and run it.

Key takeaways
  • A bash script is a file of commands the shell runs in order, saved so you can rerun them at will.
  • The #!/bin/bash shebang on the first line tells the system which interpreter runs the file.
  • set -euo pipefail makes the script stop early on errors, unset variables and failed pipelines.
  • Set variables with name=value, read them with $name, reach arguments with $1, and quote them.

Every command you have run so far, you typed one at a time. A script is nothing more than those same commands saved in a file so the computer can run them for you, in order, as many times as you like.

This bash script tutorial takes you from a blank file to a small working script that greets whoever you name, and along the way it explains the few rules that turn a plain text file into a program you can run. You are logged in as deploy in ~/data-demo on an Ubuntu 24.04 server, and everything here runs in your own home directory with no sudo needed.

What goes in the file?

Create a file called greet.sh in a text editor such as nano. Here is the whole script, and then we will read it line by line:

#!/bin/bash
set -euo pipefail

name="$1"

if [ -f orders.csv ]; then
  echo "Hello, $name. Your orders.csv is here."
else
  echo "Hello, $name. No orders.csv found."
fi

That is a complete, working script, and it is all this bash script tutorial needs to teach the essentials. Every line earns its place, so let us go through them.

The shebang tells the system what runs it

The first line, #!/bin/bash, is called the shebang. The two characters #! at the very start of a file tell the kernel which program should interpret the rest of the file. Here that program is /bin/bash, the Bash shell. Without this line the system may not know that your file is meant for Bash, so make it the first line of every script, with no blank line or space before it.

set -euo pipefail: fail early, not silently

The second line is a habit worth forming from your first script. set -euo pipefail changes three defaults that otherwise let a broken script keep running:

  • -e stops the script the moment any command fails, instead of carrying on to the next line.
  • -u treats the use of an unset variable as an error, which catches typos in variable names.
  • -o pipefail makes a pipeline fail if any command in it fails, not just the last one.

Together they turn quiet, creeping failures into loud, early ones, which is what you want. A script that stops at the first sign of trouble is easier to trust than one that pushes on and leaves a mess behind it.

Variables and arguments

A variable holds a value under a name. You set one with name=value and no spaces around the =, and you read it back by putting a $ in front, as $name. The spaces matter: name = value is read as a command called name, not an assignment.

A positional argument is a value you pass to the script when you run it. Inside the script, $1 is the first argument, $2 the second, and so on. The line name="$1" copies the first argument into a variable called name, so the rest of the script can use a clear name instead of a number.

Notice the double quotes around "$1" and "$name". Quoting a variable keeps its value as one piece even if it contains spaces. Without quotes, a name like New Delhi would be split into two words and break the command. The rule is plain: quote your variables unless you have a specific reason not to.

Testing a condition with if

The if block checks something and acts on the answer. The test here is [ -f orders.csv ], where -f asks "does this file exist and is it a regular file?". The square brackets are actually a command that returns success or failure, so the spaces inside them are required. If the file is there, the then branch runs; if not, the else branch runs. You will use [ -f file ] often to check that a file exists before a script tries to read it.

Make it executable, then run it

A fresh script is just a text file, and the system will not run it until you give it permission. Mark it executable with chmod +x greet.sh, which adds the execute bit you read about in the permissions series. Now run it by giving its path:

./greet.sh ServerCake
Running the script passes ServerCake as an argument, and the script prints a line built from the argument and a file count

The ./ in front means "the file in the current directory", which you need because your current directory is not on the PATH, for safety reasons. The word ServerCake after the script name is the first argument, so inside the script $1 becomes ServerCake and $name follows. The screenshot shows the greeting with your argument filled in, and the second half of the line depends on whether orders.csv sits in the directory, which for you it does. You have written and run a program.

Troubleshooting your first script

"bash: ./greet.sh: Permission denied". The file is not executable yet. Run chmod +x greet.sh to add the execute bit, then run it again.

"greet.sh: command not found". The shell does not look in the current directory for programs. Run it as ./greet.sh, with the leading ./, so it finds the file where you are.

"bad interpreter: /bin/bash^M: No such file or directory". The file has Windows line endings, and the ^M is a carriage return stuck to the shebang. Fix it with sed -i 's/\r$//' greet.sh, or save the file with Unix line endings.

"$1: unbound variable". set -u treats an unset variable as an error, so running the script with no argument fails. Pass one, for example ./greet.sh ServerCake, or give the variable a default value.

Frequently asked questions

Why do I have to type ./ before the script name?

The current directory is not on the PATH, for safety, so the shell will not run a program there unless you point at it explicitly with ./.

What does set -euo pipefail actually do?

-e stops the script at the first failed command, -u errors on an unset variable, and -o pipefail makes a pipeline fail if any stage fails. Together they surface problems early.

Why must there be no spaces around the = in name=value?

With spaces, the shell reads name as a command rather than an assignment. name=value with no spaces is the assignment syntax.

Why quote variables like "$name"?

Quoting keeps the value as one piece even when it contains spaces. Without quotes, a value like New Delhi splits into two words and breaks the command.

Recap

That is the whole shape of a Bash script, and the rest is more of the same. A script is a file of commands. The #!/bin/bash shebang says which interpreter runs it. set -euo pipefail makes it stop early on errors, unset variables, and failed pipelines. You set variables with name=value, read them with $name, and reach arguments with $1. Always quote variables so values with spaces stay whole.

[ -f file ] tests that a file exists before you use it. Finally chmod +x makes the file executable and ./greet.sh runs it. This bash script tutorial gave you a working example; from here you turn any sequence of commands you type often into a script that types them for you.


Skip the manual steps

Deploy a pre-hardened server

Every command in this guide, already applied. One click provisions a ServerCake VM with this hardening built in, tested, verified, ready. Launching with the platform.

Get early access

This guide is provided for educational purposes and offered as is, without warranty of any kind. The commands change the configuration of a server you control, and some can lock you out if run out of order. Test on a non-production machine, keep a second session open, and take a snapshot or backup before you begin. You are responsible for changes made to your own systems; ServerCake accepts no liability for any loss, downtime, lockout, or damage arising from following this guide or running the accompanying script.

Was this guide helpful?
Share

Spotted something out of date or have a question?

Built by the ServerCake team

Cloud that speaks India.

ServerCake is India's KYC-verified cloud: VMs and managed databases priced in ₹, billed with GST, on India-resident infrastructure. Reserve your spot for early access.

Reserve your spot