Special Bash Parameters
Tags: bash, shell, script
Published: 2023-02-26 11:12:04

It's always amazing observing experts. It often leaves you inspired, motivated and hungry for more professional growth of your own. Recently, I switched teams and now work alongside someone who has been writing bash scripts professionally for longer than I have been alive. Watching him approach problems has left me in awe.

This week, I learnt about _built-in bash parameters_ from him and thought to explore them a little more.

&ensp;

> NB: The shell treats these parameters specially. They can only be referenced. Assignment to them is not allowed. 

&ensp;

## Parameters explored
* [Asterisk - $*](#asterisk)
* [At sign - $@](#at-sign)
* [Hashtag - $#](#hashtag)
* [Question mark - $?](#question-mark)
* [Zero - $0](#zero)

&ensp;
<a name="asterisk"></a>

## 1. Asterisk *

| Variable  |  Usage  |  
| --------- | --------|
| $*        | Stores all the arguments that were entered on the command line ($1 $2 ...)| 

For example take script `foo.sh` below

```bash
#!/bin/bash

# loops over arguments and prints them in a new line
 
for i in $* ; do
  echo -e "$i\n" 
done
```
Now run the script and pass a few arguments

```shell
$ ./foo.sh arg-1 arg-2 arg-3 arg-4
arg-1

arg-2

arg-3

arg-4


# notice double quotes around "arg-2 arg-3" are ignored 
# they are treated as 2 seperate arguments

$ ./foo.sh arg-1 "arg-2 arg-3" arg-4
arg-1

arg-2

arg-3

arg-4
```

However, when we place `$*` in double quotes `"$*"` all the arguments are taken as a single string

```bash
#!/bin/bash

#notice the change with "$*"
  
for i in "$*" ; do
  echo -e "$i\n" 
done
``` 

```shell
$ ./foo.sh arg-1 arg-2 arg-3 arg-4
arg-1 arg-2 arg-3 arg-4
```
 

&ensp;
<a name="at-sign"></a>

## 2. At sign @

| Variable  |  Usage |  
| --------- |--------|
| $@        | Stores all the arguments that were entered on the command line, individually quoted ("$1" "$2" ...)| 

`$@` is similar to `$*` but with a subtle difference.

```bash
#!/bin/bash
 
for i in $@ ; do
  echo -e "$i\n" 
done
```

```shell
$ ./foo.sh arg-1 arg-2 arg-3 arg-4
arg-1

arg-2

arg-3

arg-4


# same behaviour as $*
# double quotes are ignored

$ ./foo.sh arg-1 "arg-2 arg-3" arg-4
arg-1

arg-2

arg-3

arg-4
```

However, `$@` behaviour changes when in double quotes `"$@"`

```bash
#!/bin/bash

#notice the change with "$@"
  
for i in "$@" ; do
  echo -e "$i\n" 
done
``` 

```shell

# double quotes are treated as a single argument
$ ./foo.sh arg-1 "arg-2 arg-3" arg-4
arg-1 

arg-2 arg-3 

arg-4
```

With `"$@"`, all the arguments that were entered are treated individually quoted ("$1" "$2"...) 

This is generally the behaviour we often want when writing scripts and how it differs from `$*`

&ensp;
<a name="hashtag"></a>

## 3. Hashtag \# 

| Variable  |  Usage |  
| --------- |--------|
| $#        | Stores the number of command-line arguments that were passed to the shell program.| 

Take `foo.sh` 

```bash
#!/bin/bash

echo "Number of arguments entered is : $# "
```

```shell
$ ./foo.sh arg-1 arg-2 arg-3 arg-4
Number of arguments entered is : 4


$ ./foo.sh arg-1 arg-2 
Number of arguments entered is : 2
```

&ensp;
<a name="question-mark"></a>

## 4. Question mark ?
| Variable  |  Usage |  
| --------- | ------ |
| $?        | Stores the exit value of the last command that was executed.| 

It's also called exit status and this variable stores the exit value of the last command that was executed. It is an integer number. 

If `$?` equals 0, the previously run command was successful. 
If `$?` is between 1-255, the command failed. 
If `$?` equals 127, then the command is not found.

Example usage : 

```shell
$ echo "Hello there!" > file.txt

$ cat file.txt
Hello there!

$ echo $?
0

# returns 0 as the last run command was successful.
```

```shell
$ cat non-existent-file.txt
cat: non-existent-file.txt: No such file or directory

$ echo $?
1

# returns 1 as the last run command was unsuccessful.
```

You can see the usefullness of `$?` in this urlchecker script `bar.sh` 

```bash
#!/bin/bash

curl --output /dev/null --silent ${1} && exit_code=$? || exit_code=$?

    if [ ${exit_code} -eq 0 ]; then
        echo "${1} is a valid url"
    else
        echo "Sorry, ${1} is NOT a valid url"
    fi
```
Invoking the script and passing in both valid and invalid urls

```shell
$ ./bar.sh https://www.google.com
https://www.google.com is a valid url

$ ./bar.sh https://www.not-a-valid-website.com
Sorry, https://www.not-a-valid-website.com is NOT a valid url
```

&ensp;
<a name="zero"></a>

## 5. Zero 0
| Variable  |  Usage |  
| --------- | ------ |
| $0        | Stores the name of the script that is currently being executed.| 

Take script `bar.sh` 

```bash
#!/bin/bash

echo "This is the name of this shell script : $0"
```

```shell
$ ./bar.sh
This is the name of this shell script : ./bar.sh
```

Just running in the terminal, you get :

```shell
$ echo $0
-bash
```

In essense, `$0` holds the name of the currently executing script in bash.

&ensp;

You can see more on special bash parameters from the [Bash reference manual](https://www.gnu.org/software/bash/manual/bash.html#Special-Parameters)