Threat Picture
Latest Cybersecurity News
What the $!$*$@ … Bash Shell Variables

What the $!$*$@ … Bash Shell Variables

Nobody memorizes $!, $* and $@, so here's a script that shows what each one does. Bash's special variables, demonstrated instead of defined.
By Charles Joseph · Updated
Share
Share
Copy URL

There's nothing complicated about Bash's special shell variables, so what's the problem? There's nothing memorable about them either.

Each is a dollar sign followed by a single character, and each answers one question about the script that's running: how many arguments arrived, whether the last command worked, which process ID is mine. Frankly, they're just not that interesting.

So I wrote a short script that prints every one of them side by side. For me, a working example is far easier to understand than a list of definitions, and that's how this tutorial is built.

Bash Shell Variables at a Glance

  • $* holds every argument passed to the script, separated by the first character of IFS, the shell's internal field separator.
  • $@ holds every argument as well, but separated as words.
  • $# is the number of arguments passed to the script.
  • $? is the exit status of the most recently executed foreground pipeline.
  • $- is the set of option flags the shell is currently running with.
  • $$ is the process ID of the shell.
  • $! is the process ID of the most recently executed background command.
  • $0 is the name of the shell script.
  • $_ starts out as the absolute file name of the shell or script, then becomes the last argument of the previous command.
Sponsored

The Script in Action

The Custom Script

The script does one job: it echoes each special variable beside its own name. In every echo, the first dollar sign is escaped so the label prints literally, and the second one expands to the value.

The seq and sort pipeline runs in the background, courtesy of the trailing &, for no other reason than to give $! a process ID to report.

#!/bin/bash

# Run a background job so $! contains its process ID.
# seq prints a range of numbers: seq 3 prints 1, 2, 3 on separate lines.
seq 1000000 | sort -nr > /dev/null &

echo "All arguments (\$*):       $*"
echo "All arguments (\$@):       $@"
echo "Argument count (\$#):      $#"
echo "Last exit status (\$?):    $?"
echo "Shell options (\$-):       $-"
echo "Shell process ID (\$\$):   $$"
echo "Background job PID (\$!):  $!"
echo "Script name (\$0):         $0"
echo "Previous last arg (\$_):   $_"

Two Arguments, Three Words

Notice the below two parameters passed on the command line: "I love" and "handsonkeyboard.com". That's only two arguments.

Look carefully at the quotes, though. In total, those two arguments contain three words, and the quotes are the only thing holding "I love" together as one argument. Keep that in mind when the output arrives.

Sponsored

The Script Output

All arguments ($*):       I love handsonkeyboard.com
All arguments ($@):       I love handsonkeyboard.com
Argument count ($#):      2
Last exit status ($?):    0
Shell options ($-):       hB
Shell process ID ($$):   2370055
Background job PID ($!):  2370057
Script name ($0):         ./s.sh
Previous last arg ($_):   Script name ($0):         ./s.sh

Nine lines, nine variables. Here's what each of them is telling you.

Every Variable in One Table

For reference, here's the whole set in one place, with the value each one produced in the run above.

VariableDescriptionValue from the run above
$*All arguments passed to the script, separated using the first character of the special shell variable IFS, the internal field separator.I love handsonkeyboard.com
$@All arguments passed to the script, separated as words.I love handsonkeyboard.com
$#The number of arguments passed to the script.2
$?The exit status of the most recently executed foreground pipeline.0
$-The current option flags, as set at invocation, by the set built-in command, or by the shell itself. Here h is hashall, which has Bash remember where it found each command instead of searching the path again, and B is braceexpand, which turns {1..3} into 1 2 3.hB
$$The process ID of the shell.2370055
$!The process ID of the most recently executed background command.2370057
$0The name of the shell script../shell-special-params.sh
$_At shell startup, the absolute file name of the shell or script; afterwards, the last argument to the previous command, after expansion.$0: ./shell-special-params.sh

Bash Shell Variables: Easier Run Than Memorized

Nine dollar-sign variables, nine quick answers about the script that's running: its arguments, its exit status, its options, its process IDs and its own name.

None of it is difficult, and none of it is the kind of knowledge that sticks after reading a definition.

Run the script once with a couple of quoted arguments, though, and the whole set falls into place. And if one of them slips your mind later, re-running nine lines of Bash beats re-reading nine definitions every time.

QUOTE:

"Amateurs hack systems, professionals hack people."