Sitemap

Special Parameters in Bash

--

In my last article, Intro to Bash Scripts, the concept of positional parameters was introduced. Positional parameters are arguments that are treated in a specific, predetermined manner by the Bash shell. Knowing these will allow easier access to information in your Bash scripts, and they are some of the basic building blocks of Bash knowledge.

$0

While looking like a $0 a positional parameter, $0 works a bit different than the others. Other than working differently than the rest of the positional parameters, $0 is interesting because it will work differently depending on where it is invoked. From the command line- in the Bash shell- $0 will expand to the name of the current shell.

Since this is executed in the Bash shell, it will print just “bash”.

The other use is when $0 is invoked within a Bash script, it will instead expand to the name of the script. This is extraordinarily useful in context of logging and printing out information for communication. So we can create a file called print_name.sh:

And then run this from the shell and see the name of the script being echoed:

$[1–9]

Now we are at the positional parameters. These parameters, made by combing the dollar sign ($) with a digit between 1–9, allows you to have access to arguments passed into the script. The parameters will match up with the order in which they are are passed in. A script some_script.sh being called so:
./some_script.sh x y z

will have x correspond to $1, y to $2, and z to $3. But wait- does that mean that all Bash scripts are limited to only 9 arguments? No, but past 9, the argument number will need to be enclosed in braces- i.e., for the 11th argument, you would write ${11}, not $11.

Let’s look at this in a simple script called give_info.sh which takes in some information about a person, and echos the results.

Press enter or click to view image in full size

And will allow you to to print out this statement in whichever configuration you would like:

Press enter or click to view image in full size

$*

$* will expand to all of the positional parameters into one ‘super parameter’. While that sounds simple, there are actually several different ways this can be accomplished. The first is simply putting $* in your script without any quotes, which will expand to each positional parameter separated by whitespace. This can be seen in this script expand_params.sh:

which will take in any amount of positional parameters and print them to the command line:

Press enter or click to view image in full size

You’ll notice that this is not perfectly recreated- the third argument is given as “$0” but is being printed as “bash”. This is because $* will expand any parameters that are given to it recursively. So any positional parameters, or other parameters, given to the script will be themselves expanded. Since this argument comes from the command line, it is expanding to “bash” instead of “expand_params.sh”.

Get Tom Donovan’s stories in your inbox

Join Medium for free to get updates from this writer.

The second way to use $* is within double quotes, which will still expand to all of the positional parameters but separated by the Internal Field Separator (IFS) variable. The default value of the IFS variable is a space, a tab, and a newline, but it can be changed to whatever the user wants. However, if the IFS variable is set to its default, then the parameters will be expanded like earlier, with just a space. So putting $* will only have different functionality if the IFS variable is not set to its default. Let’s edit our expand_params.sh script in order to demonstrate this functionality.

This script will echo the $* parameter in double quotes with the IFS set to its default value, then save the default value (so it can be reset later), set the IFS variable to “ — — -”, echo again, set the IFS variable to null, echo a third time, and then reset the IFS variable to its default value. Let’s see it in action:

Press enter or click to view image in full size

$@

$@ is functionally very similar to $* with one major difference. $@ will expand all positional parameters, but will expand them into an array while $* will expand them into a single parameter. Let’s use two_expands.sh to illustrate this difference.

This script will loop through the expansions of $* and $@ to show that $* expands to one param and $@ expands to an array.

Press enter or click to view image in full size

$#

$# is one of the simplest special parameters and requires little elaboration. It will print out the total number of positional parameters given to the script. Thus the script print_num_params.sh:

Will print out the number of parameters given to it:

Press enter or click to view image in full size

$?

Other than the positional parameters, $? is one of the most commonly used parameters. This will expand to the exit status of the most recent recently executed foreground pipeline. What that means, in simpler terms, is basically that $? will expand to exit status of most recently executed command. Given some script return.sh that exits with some status given to it:

And a script echo_exit.sh:

We can pass in some exit value to echo_exit.sh, execute return.sh with that value, and then check what return.sh (being the most recently executed command) exits with.

$-

$- will expand to a list of the currently enabled shell options. There are many, many shell options, and I encourage you to go through set’s documentation. A broad overview is that bash has many shell variables which control various environmental settings. These can be turned on and off with set, and you can see which are on or off with $-.

$$ and $!

These two are very similar, and so I decided to group them together. $$ expands to the process id (PID) of the shell when run in the command line, and the PID of the shell invoking the process. A PID is just a number that represents a running process. $! expands to the PID of the most recent process put into the background. So if we have a script that starts a process, process.sh:

And another script process_starter.sh that starts process.sh and puts it into the background, we can check the PIDs of the subshell invoking process.sh and process.sh.

The ampersand (&) after ./process.sh sends this process to the background immediately. Since process.sh is just an infinite loop, it must be killed explicitly on the last line. Putting this into action, we can see the two PIDS as they are created and run:

Press enter or click to view image in full size

Other Articles in This Series on Bash

--

--

Tom Donovan
Tom Donovan

Written by Tom Donovan

Software engineer who likes looking into different topics.