0

Consider file main.sh as

#!/usr/bin/bash
echo "Main PID is $$"
CMD="./helper.sh"
echo $($CMD)

consider helper.sh as

#!/usr/bin/bash
echo "PPID in helper script is $$"
echo "Bash pid is $BASHPID"

When I run ./main.sh the output is

Main PID is 867
PPID in helper script is 868 Bash pid is 868

Now my query is that the command substitution used to run helper.sh from main.sh shoud've spawned a subshell which has its own PID which'll be returned by $BASHPID but $$ must've returned the parent PID i.e. the pid of shell in which main.sh is running as is indicated by this answer.

So why is it not the case and parent pid is the same as current shell pid in helper.sh ?

  • 2
    `$$` is the process ID of the shell. What you want is `$PPID`, which is the process ID of the shell’s parent process. – M. Nejat Aydin Aug 23 '20 at 01:37
  • Exactly that. `$$` and `$BASHPID` are only different when you're in a subshell. In the top level of a shell it's normal and expected for them to be identical. And while your `helper` is _run from_ a subshell, it is itself a whole new interpreter so you're in the top level within it when you do the echo. – Charles Duffy Aug 23 '20 at 01:43

1 Answers1

1

Expected behavior for $$ is to return the top-level PID of the current shell interpreter.

When you run ./helper.sh, that's a new shell interpreter; within its top level, $$ and $BASHPID are expected to be identical. (When you start a subshell within it, $BASHPID will change but $$ will not).

Consider the following, expanded test case:

cat >main <<'EOF'
#!/usr/bin/env bash
echo "Main PID is $$"
(./helper "$$" "$BASHPID")
EOF

cat >helper <<'EOF'
#!/usr/bin/env bash
echo "Parent main PID is $1"
echo "Parent subshell PID is $2"
echo "Child main PID is $$"
echo "Child current PID is $BASHPID"
EOF

chmod +x main helper
./main

It should emit something like:

Main PID is 37596
Parent main PID is 37596
Parent subshell PID is 37597
Child main PID is 37597
Child current PID is 37597

The child's main PID is in this case the parent's subshell PID, because bash is able to recognize when it can directly exec a child process from inside a subshell. The child's current PID is the same as the child's main PID, because nothing that has been done that would create a new subshell inside the child; note that this optimization is contextually-dependent and may or may not happen, depending on traps and other active configuration.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • Thanks @Charles Duffy. There are two queries I still have in my mind 1.) Is creating a subshell different from a child process? 2.) How can we access the parent process Id directly in subshell without passing it as an argument? Will $PPID works? – Prabhat Sharma Aug 23 '20 at 02:15
  • 1
    Use `$PPID` to get the PID of the parent process. And yes, subshells are a special case of child processes: They're different because they're divided by a `fork()` but without any `exec`-family syscall. – Charles Duffy Aug 23 '20 at 02:39