Bash $$

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

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/bash

echo "\$\$ 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/bash

FILENAME=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/bash

echo "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?

Leave a Reply

Your email address will not be published. Required fields are marked *

How to Import a Python Function fro...
How to Import a Python Function from Another File