Why does echo $$ return a number?
Why does running echo $$
in bash
return a number like 7190
, while running echo $
only returns a $
?
Solution 1:
Convention.
$$
: Expands to the process ID of the shell. In a () subshell, it expands to the process ID of the invoking shell, not the subshell (see the link to the manual below).
rinzwind@schijfwereld:~$ echo $$
3244
rinzwind@schijfwereld:~$ ps -ef |grep 3244
rinzwind 3244 3237 0 19:06 pts/0 00:00:00 /bin/bash
Very useful when coding software. And it can be used as a crude (mktemp
would be the better method) way of creating temp files
1 $
has no special meaning so it gives you what echo always does: return it.
There is a manual page dedicated to this (3.4.2 Special Parameters).
Solution 2:
In bash to state using a variable we use $
, using $$
with the first dollar sign we are saying that I want to use a variable and using the second one we are telling that the name of that variable is actually a $
. it's actually a naming convention, and this variable contains the process id of the current shell.
As you asked in the comments with $$$$
you are returning the same process id twice.
There are other variables too (From here):
$1
,$2
,$3
, ... are the positional parameters."$@"
is an array-like construct of all positional parameters,{$1, $2, $3 ...}
."$*"
is the IFS expansion of all positional parameters,$1 $2 $3 ...
.$#
is the number of positional parameters.$-
current options set for the shell.$$
pid of the current shell (not subshell).$_
most recent parameter (or the abs path of the command to start the current shell immediately after startup).$IFS
is the (input) field separator.$?
is the most recent foreground pipeline exit status.$!
is the PID of the most recent background command.$0
is the name of the shell or shell script.
Solution 3:
Here is a real life application of $$
taken from Lock Screen Timer:
# Check if lock screen timer already running
pID=$(pgrep -f "${0##*/}") # All PIDs matching lock-screen-timer name
PREVIOUS=$(echo "$pID" | grep -v ^"$$") # Strip out this running copy ($$$)
if [ "$PREVIOUS" != "" ]; then
kill "$PREVIOUS"
rm ~/.lock-screen-timer-remaining
zenity --info --title="Lock screen timer already running" --text="Previous lock screen timer has been terminated."
fi
In this code snippet the line:
PREVIOUS=$(echo "$pID" | grep -v ^"$$") # Strip out this running copy
uses the current running process ($$
) to remove it (denoted by not -v
) from the list of all processes running under the same name (lock-screen-timer
in this case).
If there was a previous running copy the code kills it and delete the work file it was using.