Script Parameters

Learn how to change the Bash script's behavior using parameters.

Parametrizing the photo directory

Let’s suppose we moved our photos from the ∼/photo directory to ∼/Documents/Photo. If we want to support the new path in the backup script, we should change its code. The following shows how the new script looks:

#!/bin/bash

tar -cjf ~/photo.tar.bz2 ~/Documents/Photo &&
  echo "tar - OK" > results.txt ||
  { echo "tar - FAILS" > results.txt ; exit 1 ; }

cp -f ~/photo.tar.bz2 ~/backup &&
  echo "cp - OK" >> results.txt ||
  ! echo "cp - FAILS" >> results.txt

Every time we move the photos from one directory to another, we have to change the script. This is inconvenient. A better solution is to make a universal script that can handle any directory. Such a script would receive the path to photos as an input parameter.

When we run a Bash script, we can pass command-line parameters there. This works the same way as for any GNU utility. We specify the parameters separated by a space after the script name. Bash will pass them to the script. Here is an example:

./photo-backup.sh ~/Documents/Photo

This command runs our script with the ~/Documents/Photo input parameter. We can read it via the $1 variable in the script. If the script receives more parameters, we read them via the variables $2, $3, $4, etc. These names match the numbers of the parameters. Variables of this type are called positional parameters.

There is a special positional parameter $0. It stores the path to the launched script. It equals ./photo-backup.sh in our example.

Let’s handle the input parameter in our script. The following shows how it looks after the change:

#!/bin/bash

tar -cjf ~/photo.tar.bz2 "$1" &&
  echo "tar - OK" > results.txt ||
  { echo "tar - FAILS" > results.txt ; exit 1 ; }

cp -f ~/photo.tar.bz2 ~/backup &&
  echo "cp - OK" >> results.txt ||
  ! echo "cp - FAILS" >> results.txt

The $1 variable stores the path to the photos. We use it in the tar call. There are double quotes around the variable name. They prevent the word splitting mechanism.

Let’s suppose we want to archive photos from the ~/photo album path. Then, we call the script this way:

./photo-backup.sh "~/photo album"

Let’s suppose that we skip double quotes around the variable name when we call the script. Then the tar call looks like this:

tar -cjf ~/photo.tar.bz2 ~/photo album &&
  echo "tar - OK" > results.txt ||
  { echo "tar - FAILS" > results.txt ; exit 1 ; }

In this case, the tar utility receives the ~/photo album string in parts. It gets two parameters instead of one: ~/photo and album. These directories do not exist. Therefore, the script fails.

It is not enough to put parameters in double quotes when calling a script. We should quote all occurrences of the corresponding variable name in the script. This happens because of the way Bash runs a program.

Let’s suppose that we call a script from the shell. Then, Bash spawns a child process to execute it. The child process does not receive quotes from the command line because Bash removes them. Therefore, we should add quotes again inside the script.

Now, our backup script can handle the input parameter. What are the benefits of this solution? It provides us a universal script for making backups. The script can process any paths and types of input files: documents, photos, videos, source code, and so on.

However, adding parameter processing to our script leads to one problem. Let’s suppose we call it twice to makebackups of our photos and documents like this:

./photo-backup.sh ~/photo
./photo-backup.sh ~/Documents

The first command creates the ~/photo.tar.bz2 archive and copies it to the ~/backup directory. Then, the second command does the same and overwrites the existing ~/backup/photo.tar.bz2 file. This way, we lose the result of the first command.

Get hands-on with 1400+ tech skills courses.