Skip to content

Intermediate · Automation basics: scheduling, archives and shell scripts · topic 37 of 57 · 35 min

Bash scripts: variables, quoting, arguments and exit codes

Explanation

A shell script is a text file of commands that starts with #!/bin/bash and is made executable with chmod +x. Variables hold text ($name), command substitution captures output ($(date)), $1 $2 and $@ are the script's arguments, and $? is the exit code of the last command: 0 means success.

Why scripts?

If you type the same ten commands every week, put them in a script. It runs the same way every time, anyone on the team can run it, and cron or a timer can run it at night. Bash scripts are the glue of Linux administration.

Your first script

bash
$ cat > ~/bin/hello.sh << 'EOF'
#!/bin/bash
# hello.sh: greet the user and show the date
echo "Namaste, $USER"
echo "Today is $(date +%A)"
EOF
$ chmod +x ~/bin/hello.sh
$ ~/bin/hello.sh
Namaste, asha
Today is Monday
The first line (the shebang, #!) says which program runs the script. ~/bin is in PATH on RHEL, so plain hello.sh works too.

Variables

bash
name="Asha Rao"          # NO spaces around =
count=3
echo "$name has $count tickets"
today=$(date +%F)        # command substitution: the output of date
backup="/backup/etc-$today.tar.gz"
echo "Writing $backup"
echo "${name}_report"     # braces separate the name from text after it

name = "x" (with spaces) is an error: bash tries to run a command called name. Variables are text by default. For whole-number maths use $(( )): total=$(( count * 250 )).

Quoting rules

QuoteWhat happensExample
"double"Variables and $( ) are expanded; spaces are kept"$name" → Asha Rao
'single'Nothing is expanded; text is taken literally'$name' → $name
noneExpanded, then split on spaces and wildcards expanded$name → two words: Asha, Rao
Careful: Always put variables in double quotes: rm "$file", not rm $file. If $file is "my report.txt", the unquoted version tries to remove two files, "my" and "report.txt". If it is empty, some commands act on the wrong thing entirely.

Arguments

bash
#!/bin/bash
# greet.sh NAME [CITY]
echo "Script: $0"
echo "First argument: $1"
echo "Second argument: ${2:-Pune}"   # use Pune if $2 is empty
echo "Number of arguments: $#"
echo "All arguments: $@"
$ ./greet.sh Ravi Chennai
Script: ./greet.sh
First argument: Ravi
Second argument: Chennai
Number of arguments: 2
All arguments: Ravi Chennai

read asks the user for input: read -p "Username: " user. For scripts run by cron, prefer arguments or a config file; nobody is there to type.

Exit codes

Every command ends with an exit code (exit status), a number from 0 to 255. 0 means success; anything else means some kind of failure. $? holds the code of the last command. Your script should end with exit 0 on success and a non-zero code on failure, so cron, systemd and other scripts can tell what happened.

bash
$ grep -q asha /etc/passwd; echo $?
0
$ grep -q nobodyhere /etc/passwd; echo $?
1
$ ls /nope; echo $?
ls: cannot access '/nope': No such file or directory
2
$ mkdir /backup && echo "created"       # && runs the next one only on success
$ ping -c1 db01 || echo "db01 is down"  # || runs the next one only on failure

Common mistakes

  • Spaces around = in an assignment.
  • Forgetting chmod +x, then getting "Permission denied". Or running a script written on Windows: "bad interpreter: /bin/bash^M" means Windows line endings; fix with sed -i "s/\r$//" script.sh.
  • Using unquoted variables.
  • Not setting an exit code, so a failed backup looks successful to cron.
Tip: Run bash -n script.sh to check the syntax without running it, and bash -x script.sh to see every line as it runs. shellcheck (from EPEL) finds many common bugs.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Bash scripts: variables, quoting, arguments and exit codes · 1/7

#!/bin/bash

A script is a file of commands. The first line, the shebang, says bash runs it.

Prefer a video by a teacher? Find free videos on “bash scripting tutorial variables arguments exit codes beginners” on YouTube ↗

In real life: A user-creation script for a BPO in Gurugram

A BPO in Gurugram onboards 30 agents every Monday. The admin writes add-agent.sh NAME TEAM: it checks it got two arguments, creates the user in the team group, sets a temporary password that must be changed, and exits with 1 and a clear message if anything fails. The HR coordinator's list is turned into 30 calls of the script.

bash
#!/bin/bash
if [ $# -ne 2 ]; then
    echo "Usage: $0 NAME TEAM" >&2
    exit 2
fi
useradd -G "$2" "$1" || exit 1
echo "$1:Welcome@123" | chpasswd && chage -d 0 "$1"
echo "Created $1 in $2"
exit 0
Errors go to stderr with >&2; usage errors exit 2, failures exit 1.

Practice (0/3 done)

Task 1 · Question

Which line correctly sets a variable?

Task 2 · Question

name='Asha'. What does echo '$name' print?

Task 3 · Code · Python

Model a script's argument check in Python. Write check_args(args) where args is the list of arguments (like $@). The script needs exactly 2 arguments: NAME and TEAM, and NAME must not be empty. Return a tuple (exit_code, message): (2, "Usage: add-agent NAME TEAM") if the count is wrong, (1, "NAME is empty") if NAME is "", otherwise (0, "Creating NAME in TEAM") with the real values.

Quick quiz

Question 1

1.What does $# hold in a script?

Question 2

2.What exit code means success?

Question 3

3.What does "mkdir /x && echo ok" do if mkdir fails?

Question 4

4.Why write rm "$file" instead of rm $file?

Question 5

5.What does $(hostname) do inside a script?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

What does $# hold in a script?

Answer: The number of arguments

$# is the argument count.

What exit code means success?

Answer: 0

0 = success.

What does "mkdir /x && echo ok" do if mkdir fails?

Answer: Does not print ok

&& runs the second command only if the first succeeds.

Why write rm "$file" instead of rm $file?

Answer: A file name with spaces stays one argument

Unquoted variables are split on spaces.

What does $(hostname) do inside a script?

Answer: Runs hostname and puts its output there

Command substitution.

FILE="monthly report.csv". Why is rm $FILE dangerous?Related

Answer: Without quotes it splits into two arguments, "monthly" and "report.csv"

Unquoted variables are split on spaces. Always write rm "$FILE".

From Bash scripting, text tools and cron

Which shows a list of earlier commands?Related

Answer: history

history lists commands you ran; !N runs number N again.

From Shell basics and getting help

Which loop reads a file line by line correctly?Related

Answer: while read -r l; do ... done < f

while read -r handles lines with spaces.

From Bash scripts: conditions, loops and safe habits

What exit code means success?Related

Answer: 0

Zero is success; non-zero is failure.

From Command-line tools with flag and os

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 1 more topic in “Automation basics: scheduling, archives and shell scripts” before its exam: Bash scripts: conditions, loops and safe habits.
  2. Module 7 exam: Automation basics · 14 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Boot, recovery and containers. 57 topics left in the course before the final exam.

← Previous: Archives and compression: tar, gzip, bzip2 and xz