In bash you have this handy variable: $BASHPID wich always returns the currently running subshell's PID. How can I get a subshell's PID in ksh? For example see the code below:


echo "PID at start: $$"

function run_in_background {
  echo "PID in run_in_background $$"
  run_something &
  echo "PID of backgrounded run_something: $!"

function run_something {
  echo "*** PID in run_something: $$"
  sleep 10;

echo "PID of run in background $!"

This outputs the following:

PID at start: 5328
PID in run_in_background 5328
*** PID in run_something: 5328
PID of backgrounded run_something: 5329
PID of run in background 5329

What I want is the line starting with **** to output the subshell's PID, in the example's case that would be 5329.

5 Answers 5


I don't think that's available in ksh. There's a POSIX solution which involves running an external process:

sh -c 'echo $PPID'

On Linux, readlink /proc/self would also work, but I fail to see any advantage (it might be marginally faster; it could be useful on a BusyBox variant that has readlink but not $PPID, but I don't think there is one).

Note that in order to get the value in the shell, you need to be careful not to run that command in a short-lived sub-sub-shell. For example, p=$(sh -c 'echo $PPID') might show the output of the subshell that invokes sh within the command substitution (or it might not, some shells optimize that case). Instead, run

p=$(exec sh -c 'echo $PPID')
  • I saw this suggestion already but it is not working. It gives me a third PID ... however I will test it again Monday when I'm back at work. Feb 25, 2012 at 15:45
  • @PatkosCsaba In ksh it would probably work because ksh optimizes forks, but in some other shells such as bash you need to be careful not to accidentally get the pid of a sub-sub-shell. See my updated answer. Feb 25, 2012 at 20:08
  • This is working: $(exec sh -c 'echo $PPID') However the initial simple command sh -c 'echo $PPID' gives a third PID. So thanks for the solution. Accepted. Feb 27, 2012 at 8:29
  • 1
    @FranklinYu That's because neither is creating a subshell. Bash optimizes (sh -c 'echo $PPID') to avoid creating a subshell. Contrast with (sh -c 'echo $PPID'; true). This optimization only kicks in if you try to access $BASHPID as the very last thing before the subshell exits, i.e. only in cases where you can't do anything with the value. So in practice, you can replace $BASHPID with $(sh -c 'echo $PPID'). Aug 22, 2018 at 17:32
  • 1
    @FranklinYu I don't think there's anything built in. You can of course use the portable method sh -c 'echo $PPID'. Aug 22, 2018 at 18:41

You can achieve what you want, but you need to put run_something into a separate script. I'm not exactly sure why, but $$ is not re-evaluated when it is used in a function in the same script that is calling it. I guess that the value of $$ is assigned once after the script is parsed and before it is executed.


echo "PID at start: $$"

    function run_in_background {
      echo "PID in run_in_background $$"
      ./run_something.sh &
      echo "PID of backgrounded run_something: $!"

    echo "PID of run in background $!"


echo "*** PID in run_something: $$"
sleep 10;


PID at start: 24395
PID in run_in_background 24395
PID of backgrounded run_something: 24396
PID of run in background 24396
*** PID in run_something: 24396
# KSH_VERSION hasn't always been a nameref, nor has it always existed.
# Replace with a better test if needed. e.g.:
# https://www.mirbsd.org/cvs.cgi/contrib/code/Snippets/getshver?rev=HEAD
if [[ ${!KSH_VERSION} == .sh.version ]]; then
    # if AT&T ksh
    if builtin pids 2>/dev/null; then # >= ksh93 v- alpha
        function BASHPID.get { .sh.value=$(pids -f '%(pid)d'); }
    elif [[ -r /proc/self/stat ]]; then # Linux / some BSDs / maybe others
        function BASHPID.get { read -r .sh.value _ </proc/self/stat; }
    else # Crappy fallback
        function BASHPID.get { .sh.value=$(exec sh -c 'echo $PPID'); }
elif [[ ! ${BASHPID+_} ]]; then
   echo 'BASHPID requires Bash, ksh93, or mksh >= R41' >&2
   exit 1
  • Two nitpicks: if [[ ${!KSH_VERSION} = .sh.version ]]; then (only one =) and elif [[ -z ${BASHPID+_} ]]; then (avoid using the implicit -n in double-square-brackets, old pdksh didn’t know it).
    – mirabilos
    Feb 27, 2014 at 14:06

Following the answer by @Gilles which I encountered whilst solving another problem that I had, I threw together a quick test program that underpins the theory that the correct answer is:

MYPID=$(exec sh -c 'echo $PPID')

I found there are times when exec isn't required but I confirmed that using it is the only way to get the correct pid all of the time in all of the shells I tried. Here is my test:

pids() {
  echo ------
  pstree -pg $PPID
  echo 'PPID = ' $PPID
  echo '$$ = ' $$
  echo -n 'sh -c echo $PPID = '; sh -c 'echo $PPID'
  echo -n '$(sh -c '\''echo $PPID'\'') = '; echo $(sh -c 'echo $PPID') 
  echo -n '$(exec sh -c '\''echo $PPID'\'') = '; echo $(exec sh -c 'echo $PPID') 
  echo -n 'p=$(sh -c '\''echo $PPID'\'') = '; p=$(sh -c 'echo $PPID') ; echo $p
  echo -n 'p=$(exec sh -c '\''echo $PPID'\'') = '; p=$(exec sh -c 'echo $PPID') ; echo $p
pids | cat
echo -e "$(pids)"

and its output

PPID =  5975
$$ =  13474
BASHPID = 13474
sh -c echo $PPID = 13474
$(sh -c 'echo $PPID') = 13474
$(exec sh -c 'echo $PPID') = 13474
p=$(sh -c 'echo $PPID') = 13474
p=$(exec sh -c 'echo $PPID') = 13474
PPID =  5975
$$ =  13474
BASHPID = 13481
sh -c echo $PPID = 13481
$(sh -c 'echo $PPID') = 13481
$(exec sh -c 'echo $PPID') = 13481
p=$(sh -c 'echo $PPID') = 13481
p=$(exec sh -c 'echo $PPID') = 13481
PPID =  5975
$$ =  13474
BASHPID = 13489
sh -c echo $PPID = 13489
$(sh -c 'echo $PPID') = 13492
$(exec sh -c 'echo $PPID') = 13489
p=$(sh -c 'echo $PPID') = 13495
p=$(exec sh -c 'echo $PPID') = 13489

Substitute your favourite shell in the shebang: sh, bash, mksh, ksh, etc...

I don't understand why cases 2 and 3 give different results, nor why the results for case 3 differ between shells. I tried bash, ksh and mksh on Arch Linux FWIW.

 function os_python_pid {
/usr/bin/python  -c 'import os,sys ; sys.stdout.write(str(os.getppid()))'
function os_perl_pid {
/usr/bin/perl -e 'print getppid'

echo "I am $$"
    echo "I am $(os_python_pid) :: $(os_perl_pid)"
function proce {
  sleep 3
  echo "$1 :: $(os_python_pid) :: $(os_perl_pid)"

for x in aa bb cc; do
  proce $x &
  echo "Started: $!"

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .