Bash $$ Variable: What Does It Mean? How Can You Use it? — Codefather

Bash has several internal variables and in this article we will look at the variable $$. What does this variable mean? How can you use it?

$$ is a Bash internal variable that contains the Process ID (PID) of the shell running your script. Sometimes the $$ variable gets confused with the variable $BASHPID that contains the PID of the current Bash shell.

Let’s go through some examples that will clarify what $$ is. We will also see how you can use this variable in your Bash scripts.

Let’s get started!

The Meaning of $$ in Bash

As mentioned above…

The variable $$ in Bash contains the Process ID (PID) of the shell running your script.

To show this concept we will create a very simple script that uses the grep command to print its own PID. Then the script will also use the echo command to print the value of the variable $$.

In this way we will be able to compare their values.

#!/bin/bash

SCRIPT_NAME=$(basename $0)
echo "The name of this script is $SCRIPT_NAME"
echo "This is the output of the ps command:"
ps -aef | grep $SCRIPT_NAME
echo "The value of \$\$ is $$"

The output of our shell script is:

$ ./bash_pid.sh
The name of this script is bash_pid.sh
This is the output from the ps command:
myuser 32385 31721 0 17:14 pts/0 00:00:00 /bin/bash ./bash_pid.sh
myuser 32388 32385 0 17:14 pts/0 00:00:00 grep bash_pid.sh
The value of $$ is 32385

You can see that the value of $$ is the same as the PID of the Bash process that runs the current script (32385).

The third column of the ps output is the PPID (Parent Process ID) that in this case is the PID of the current Bash shell (or Bash process):

$ ps -aef | grep 31721
myuser 31721 31323 0 16:31 pts/0 00:00:00 bash
myuser 32437 31721 0 17:17 pts/0 00:00:00 ps -aef
myuser 32438 31721 0 17:17 pts/0 00:00:00 grep --color=auto 31721

You can see the same value by using the echo command in the current shell:

$ echo $$
31721

Difference Between $$ and BASHPID

I was looking at the Bash manual to see if I could find anything more about $$.

$ man bash

And here is what I’ve found:

Let’s see if the BASHPID shell variable contains the same value as $$:

$ echo $$
31721
$ echo $BASHPID
31721

In this case it does (as we have seen before this is the PID of the current shell).

Now, let’s add the following line at the end of the previous script and rerun the script:

echo "The value of \$BASHPID is $BASHPID"

The output is:

$ ./bash_pid.sh
The name of this script is bash_pid.sh
This is the output from the ps command:
myuser 32495 31721 0 17:20 pts/0 00:00:00 /bin/bash ./bash_pid.sh
myuser 32498 32495 0 17:20 pts/0 00:00:00 grep bash_pid.sh
The value of $$ is 32495
The value of $BASHPID is 32495

$BASHPID also gives the PID of the Bash shell used to execute the current script.

So, to recap, the value of the variables $$ and BASHPID is:

  • The PID of the current shell when we look at their value directly in the shell.
  • The PID of the shell used to run the current script when the print their value inside a script.

The Value of $$ and BASHPID in Subshells

We will now compare the value of $$ and BASHPID if you use subshells.

#!/bin/bash

echo "\$\$ outside the subshell: $$"
echo "\$BASHPID outside the subshell: $BASHPID"
(
echo "\$\$ inside the subshell: $$"
echo "\$BASHPID inside the subshell: $BASHPID"
)

This is the output of the script:

$ ./subshell.sh 
$$ outside the subshell: 3145
$BASHPID outside the subshell: 3145
$$ inside the subshell: 3145
$BASHPID inside the subshell: 3146

So, when using a subshell the value of $$ is different from BASHPID.

Let’s use the ps command to understand how the PIDs returned by $$ and BASHPID in the script relate to the processes running on our system.

The script becomes:

#!/bin/bashecho "\$\$ outside the subshell: $$"
echo "\$BASHPID outside the subshell: $BASHPID"
ps -aef | grep $$
(
echo "\$\$ inside the subshell: $$"
echo "\$BASHPID inside the subshell: $BASHPID"
ps -aef | grep $$
ps -aef | grep $BASHPID
)

In the output you can see that when executed in a subshell, $$ returns the parent PID of the subshell.

$ ./subshell.sh
$$ outside the subshell: 32586
$BASHPID outside the subshell: 32586
myuser 32586 31721 0 17:29 pts/0 00:00:00 /bin/bash ./subshell.sh
myuser 32587 32586 0 17:29 pts/0 00:00:00 ps -aef
myuser 32588 32586 0 17:29 pts/0 00:00:00 grep 32586
$$ inside the subshell: 32586
$BASHPID inside the subshell: 32589
myuser 32586 31721 0 17:29 pts/0 00:00:00 /bin/bash ./subshell.sh
myuser 32589 32586 0 17:29 pts/0 00:00:00 /bin/bash ./subshell.sh
myuser 32591 32589 0 17:29 pts/0 00:00:00 grep 32586
myuser 32593 32589 0 17:29 pts/0 00:00:00 grep 32593

Bash Command and $$ Variable

I know, this can be a tough topic to understand…

For this reason I want to go through as many examples as possible to give you clarity about the $$ variable in Bash.

Have a look at the commands below:

$ echo $$
10267
$ bash -c 'echo $$'
10363

What is the difference between the two commands?

To understand that we can also run ps as part of each command:

$ echo $$; ps -aef | grep $$
31721
myuser 31721 31323 0 16:31 pts/0 00:00:00 bash
myuser 32726 31721 0 17:38 pts/0 00:00:00 ps -aef
myuser 32727 31721 0 17:38 pts/0 00:00:00 grep --color=auto 31721
$ bash -c 'echo $$; ps -aef | grep $$'
32731
myuser 32731 31721 0 17:39 pts/0 00:00:00 bash -c echo $$; ps -aef | grep $$
myuser 32732 32731 0 17:39 pts/0 00:00:00 ps -aef
myuser 32733 32731 0 17:39 pts/0 00:00:00 grep 32731

Here are few things we can observe:

  • We have used the semicolon (;) to execute two Linux commands sequentially (echo and ps).
  • The value of $$ in the current shell returns the PID of the Bash shell (as we have seen before).
  • The command bash -c executes the command within quotes in a new shell. The parent of the new shell is our initial shell.
  • In the second command, the $$ variable contains the PID of the new shell executing the commands.

$$ vs Mktemp For Temporary Directories

Sometimes, the $$ variable is used to generate temporary filenames in Linux.

Let’s say, for example, that you want to create a backup script that is executed daily and that writes the list of files included in each backup to a file.

You could use the $$ variable to generate the name of the file for the backup report considering that $$ contains the PID of the script every time it’s executed.

#!/bin/bashFILENAME=daily_backup.$$
touch $FILENAME

After running the script three times we see the following files in the current directory:

$ ./backup.sh
$ ./backup.sh
$ ./backup.sh
$ ls
backup.sh daily_backup.855 daily_backup.857 daily_backup.859

We have three different files because a different PID is assigned to the script every time the script is executed.

As an alternative, Linux provides the mktemp command.

$ mktemp
/tmp/tmp.elqilKRddX

As you can see, it generates a random temporary file under the /tmp directory.

If you want to create a temporary file in the current directory using mktemp you can do that by passing the tmpdir flag:

$ mktemp --tmpdir=.
./tmp.V5intPTQHd

Killing a Bash Script Using $$

I want to complete this tutorial with an interesting experiment…

I would like to use the $$ variable to write a script that kills itself. This is something you might never do but it gives you a better understanding of the way Bash works.

We know that the variable $$ contains the PID of the shell executing our script.

So, what happens if we kill the PID returned by $$ inside a script?

Let’s find out!

#!/bin/bashecho "The PID of this script is $$"
echo "Killing this script using \$\$…"
kill $$
echo "This should never be executed"

We are passing the PID of the current script to the kill command to terminate it.

I have added an echo command at the end of the script that should never be executed if the script gets killed successfully.

$ ./self_kill.sh
The PID of this script is 17285
Killing this script using $$…
Terminated: 15

The shell sends a “Terminated” message to the standard output. This message depends on how we kill the process.

What is the exit status returned by this script after being terminated?

$ echo $?
143

The Bash exit code 143 is due to the fact that the script terminates with a fatal signal and in these cases Bash returns an exit code equal to 128 + N.

N in this case is 15 that, looking at the output of kill -l, represents SIGTERM.

$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
5) SIGTRAP 6) SIGABRT 7) SIGEMT 8) SIGFPE
9) SIGKILL 10) SIGBUS 11) SIGSEGV 12) SIGSYS
13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGURG
17) SIGSTOP 18) SIGTSTP 19) SIGCONT 20) SIGCHLD
21) SIGTTIN 22) SIGTTOU 23) SIGIO 24) SIGXCPU
25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH
29) SIGINFO 30) SIGUSR1 31) SIGUSR2

If we use kill -9 in our script, we see a slightly different output:

$ ./self_kill.sh
The PID of this script is 18102
Killing this script using $$…
Killed: 9
$ echo $?
137

In this case the exit status $? is 128 + 9 = 137 (SIGKILL).

Conclusion

I hope you have found in this tutorial what you were looking for and that it has given you enough clarity to work with the $$ variable in Bash.

And you, how are you planning to use $$ in your scripts?

Originally published at https://codefather.tech on February 7, 2021.

I’m a Tech Lead, Software Engineer and Programming Coach. I want to help you in your journey to become a Super Developer!

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store