4

This question already has an answer here:

How can I get the pid of a subshell?

For example:

$ echo $$
16808

This doesn't work, because the original shell expands $$:

$ ( echo $$ )
16808

Why does single quoting not work? After the original shell removes the single quote, does the subshell not expand $$ in itself?

$ ( echo '$$' )
$$

Why does eval not work either? Is eval run by the subshell? Why does it give me the original shell's PID?

$ ( eval echo '$$' )
16808

Thanks.

marked as duplicate by elbarna, RalfFriedl, roaima, Isaac, thrig Nov 28 '18 at 0:50

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

3

In addition to bash's $BASHPID, you can do it portably with:

pid=$(exec sh -c 'echo "$PPID"')

Example:

(pid=$(exec sh -c 'echo "$PPID"'); echo "$$ $pid")

You can make it into a function:

# usage getpid [varname]
getpid(){
    pid=$(exec sh -c 'echo "$PPID"')
    test "$1" && eval "$1=\$pid"
}

Notice that some shells (eg. zsh or ksh93) do NOT start a subprocess for each subshell created with (...); in that case, $pid may be end up being the same as $$, which is just right, because that's the PID of the process getpid was called from.

  • Thanks. By portably, you mean ...? – Tim Nov 27 '18 at 15:13
  • Should work in any POSIX shell -- eg in debian's /bin/sh (dash) and in busybox (ash). – mosvy Nov 27 '18 at 15:15
  • 1
    No. But please do not assume that a subshell is necessarily run in a subprocess -- that is not the case in ksh93, for instance. – mosvy Nov 27 '18 at 15:18
  • 1
    It will work fine in ksh93 -- it will always return the pid of the process it was called from. It's the (...) from the example which may not spawn a separate process, as it does in bash. – mosvy Nov 27 '18 at 15:21
  • 1
    Also, some shells like zsh or yash optimise out a fork() for the last command in a subshell. They may even optimise out the fork for the subshell if it's the last command in a script so your getpid could even report the parent of $$. You could define getpid as: getpid(){ sh -c 'echo "$PPID"'; return; } to disable avoid the problem. – Stéphane Chazelas Nov 27 '18 at 16:01
13
$ echo $BASHPID
37152
$ ( echo $BASHPID )
18633

From the manual:

BASHPID

Expands to the process ID of the current bash process. This differs from $$ under certain circumstances, such as subshells that do not require bash to be re-initialized.

$

Expands to the process ID of the shell. In a () subshell, it expands to the process ID of the current shell, not the subshell.

Related:

  • Thanks. (1) What does "re-initialized" mean? (2) Could you also consider why those ways I have tried do not work? – Tim Nov 27 '18 at 13:36
  • @Tim I believe this is answered by Gilles here. Bash simply does not update $$ in subshells. – Kusalananda Nov 27 '18 at 13:44
  • Do you mean I should always use $BASHPID in place of $$ in any case in bash? When shall I use which? – Tim Nov 27 '18 at 14:09
  • @Tim It depends on whether you, in a subshell, wants to get the process ID of the script or of the subshell. Both possibilities are provided and which is the correct one is dependent on the application. No more specific answer can be given to that. – Kusalananda Nov 27 '18 at 14:20
  • 1
    @Tim The PID of a parent shell of a subshell can't reliably be found unless you arrange to save $BASHPID in a variable and use that in the subshell. There is $PPID, but that's the parent PID of the shell in the same sense that $$ is the PID of the shell (it's not reset in a subshell). There is no $BASHPPID variable. – Kusalananda Nov 27 '18 at 14:57

Not the answer you're looking for? Browse other questions tagged or ask your own question.