How can I get the pid of a subshell?

For example:

$ echo $$

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

$ ( echo $$ )

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 '$$' )


  • I suggest a reopen, because the questions are essentially different in my opinion ("how to avoid $$ expansion" vs. "different pid in subshell").
    – peterh
    Jun 19, 2019 at 3:49

3 Answers 3

$ echo $BASHPID
$ ( echo $BASHPID )

From the manual:


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.


  • Thanks. (1) What does "re-initialized" mean? (2) Could you also consider why those ways I have tried do not work?
    – Tim
    Nov 27, 2018 at 13:36
  • 1
    @Tim I believe this is answered by Gilles here. Bash simply does not update $$ in subshells.
    – Kusalananda
    Nov 27, 2018 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, 2018 at 14:09
  • 1
    If I want to get the parent pid of a subshell, that is, the pid of the invoking shell of the subshell, do I have to use $$? Can I use something else which is more predictable?
    – Tim
    Nov 27, 2018 at 14:26
  • 2
    @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, 2018 at 14:57

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

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


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

You can make it into a function:

# usage getpid [varname]
    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.

  • 1
    Should work in any POSIX shell -- eg in debian's /bin/sh (dash) and in busybox (ash).
    – mosvy
    Nov 27, 2018 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, 2018 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, 2018 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. Nov 27, 2018 at 16:01
  • 1
    @HaroldFischer 1. without the exec or without that optimization, the sh -c ... process will be a grandchild, instead of a child of the process where a $(...) command substitution is used, and $PPID will be the pid of the $(...) subshell. That's exactly what happens in the set -E + trap ERR bash example above.
    – mosvy
    Jan 5, 2020 at 7:31

On Linux a cross-shell solution (at least dash, bash, zsh) which does not spawn a new process is

read -r this_pid < /proc/self/stat; echo ${this_pid%% *}

At least in bash and zsh we can also use space as read-delimeter:

read -d ' ' this_pid < /proc/self/stat ; echo $this_pid

See also man 5 proc section /proc/[pid]/stat

  • Yeah, seems so. I guess that's a nice replacement for the first one (though it's probaly less performant than the second one).
    – spawn
    Oct 26, 2021 at 15:11
  • Thanks, that's good to know. Then the opposite is likely true.
    – spawn
    Oct 26, 2021 at 15:38
  • I just checked with strace (on Debian Buster with bash 5.0). Using your read yields three read-syscalls (at most 128 bytes at a time) read -d ' ' six (indeed one byte at a time). Dash on the other hand is not cheating. IFS=' ' read .. does read one byte at a time ...
    – spawn
    Oct 26, 2021 at 15:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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