Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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:

#!/usr/bin/ksh93

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;
}    

run_in_background
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.

share|improve this question

3 Answers 3

up vote 6 down vote accepted

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')
share|improve this answer
    
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. –  Patkos Csaba Feb 25 '12 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. –  Gilles Feb 25 '12 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. –  Patkos Csaba Feb 27 '12 at 8:29
# 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'); }
    fi
elif [[ ! ${BASHPID+_} ]]; then
   echo 'BASHPID requires Bash, ksh93, or mksh >= R41' >&2
   exit 1
fi
share|improve this answer
    
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 at 14:06
    
@mirabilos I'm stubborn about my preference for ==. No sympathy for [ + == users, and austingroupbugs.net/view.php?id=375 is still in the works anyway. If people are still using pdksh then I blame you. Work harder! The bigger issue is zsh's missing implicit -n even in emulation modes. Depending on my mood I also use ! ${var+false}, [[ ! ${var+_} ]], or [[ -v var ]] (which you don't support either. Get cracking!) –  ormaaj May 2 at 11:27

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.

run_in_background.sh

#
echo "PID at start: $$"

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

    run_in_background
    echo "PID of run in background $!"

run_something.sh

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

output

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
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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