191

I have problem with Bash, and I don't know why.
Under shell, I enter:

echo $$    ## print 2433
(echo $$)  ## also print 2433
(./getpid) ## print 2602

Where getpid is a C program to get current pid, like:

   int main() {
    printf("%d", (int)getpid());
    return 0;
   }

What confuses me is that:

  1. I think "(command)" is a sub-process (am i right?), and i think its pid should be different with its parent pid, but they are the same, why...
  2. When I use my program to show pid between parenthesis, the pid it shows is different, is it right?
  3. Is $$ something like macro?

Can you help me?

Manuel Jordan
  • 15,253
  • 21
  • 95
  • 158
ruanhao
  • 4,663
  • 6
  • 28
  • 43
  • 12
    Note that `getpid` would show a different process ID even if it weren't run in a subshell. – chepner Jan 11 '14 at 15:06
  • 3
    @Marian `echo $$ $BASHPID ; ( echo $$ $BASHPID )` demonstrates that it does. Round brackets create a subshell. The statements may change variable values, and the parent shell must not see those changes. This is implemented as a `fork()` operation. – Ben Jan 18 '20 at 10:45

8 Answers8

255

$$ is defined to return the process ID of the parent in a subshell; from the man page under "Special Parameters":

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

In bash 4, you can get the process ID of the child with BASHPID.

~ $ echo $$
17601
~ $ ( echo $$; echo $BASHPID )
17601
17634
chepner
  • 497,756
  • 71
  • 530
  • 681
  • 29
    "parent" is a bit misleading (at least it was to me), it's actually the "top level" shell. For instance : `echo $$; (echo $$; (echo $$))` echoes the same pid three times – Martin Bouladour Jul 20 '17 at 09:59
  • 1
    Right; I should have said that the value is inherited from a parent shell (which inherited its value from *its* parent, etc). The top level shell sets it initially, rather than inheriting from its (non-shell) parent process. – chepner Jul 20 '17 at 11:38
  • `$ Expands to the process ID of the shell` does it tho? `echo $` just echoes the literal $. – Alexander Mills May 31 '19 at 20:47
  • @AlexanderMills Well, yes; `$` alone is not a parameter expansion. The man page is referring to the *name* of the special parameter, which is `$`; it's not claiming that `$` alone expands. – chepner May 31 '19 at 20:55
  • 1
    Ok I honestly have no idea what that means, but `echo $BASHPID` works in bash 4 and 5 (but not version 3.2.57 on MacOS) – Alexander Mills May 31 '19 at 20:56
  • 2
    All parameter expansions start with `$`, but `$` is also the name of one of the special parameters. `$`, `#`, `@`, `*`, etc are some of the special parameters; `$$`, `$#`, `$@`, `$*`, etc are the expressions that expand to the value of each. – chepner May 31 '19 at 20:58
85

You can use one of the following.

  • $! is the PID of the last backgrounded process.
  • kill -0 $PID checks whether it's still running.
  • $$ is the PID of the current shell.
gnuanu
  • 2,252
  • 3
  • 29
  • 42
craken
  • 1,411
  • 11
  • 16
  • 3
    Shouldn't the second bullet be `kill -0 $!` if we're talking about background processes? `PID` isn't set to anything by default. – Isaac Freeman Sep 12 '19 at 22:27
30
  1. Parentheses invoke a subshell in Bash. Since it's only a subshell it might have the same PID - depends on implementation.
  2. The C program you invoke is a separate process, which has its own unique PID - doesn't matter if it's in a subshell or not.
  3. $$ is an alias in Bash to the current script PID. See differences between $$ and $BASHPID here, and right above that the additional variable $BASH_SUBSHELL which contains the nesting level.
Community
  • 1
  • 1
Niels Keurentjes
  • 41,402
  • 9
  • 98
  • 136
8

Try getppid() if you want your C program to print your shell's PID.

Alex
  • 635
  • 6
  • 15
  • Or if you use Rust just try `nix::unistd::getppid()` which will get the pid of current processes' parent - https://docs.rs/nix/0.18.0/nix/unistd/fn.getppid.html – joseluisq Oct 12 '20 at 08:08
4

this one univesal way to get correct pid

pid=$(cut -d' ' -f4 < /proc/self/stat)

same nice worked for sub

SUB(){
    pid=$(cut -d' ' -f4 < /proc/self/stat)
    echo "$$ != $pid"
}

echo "pid = $$"

(SUB)

check output

pid = 8099
8099 != 8100
ARTEM LAPKIN
  • 49
  • 1
  • 2
  • 1
    Nice idea, but won't that get you the pid of the fork the shell has run to capture the output of cut? If I run it twice, once with echo $(...) and once without, then I get different answers. – Martin Dorey Aug 26 '19 at 21:23
1

If you were asking how to get the PID of a known command it would resemble something like this:

If you had issued the command below #The command issued was ***

dd if=/dev/diskx of=/dev/disky


Then you would use:

PIDs=$(ps | grep dd | grep if | cut -b 1-5)

What happens here is it pipes all needed unique characters to a field and that field can be echoed using

echo $PIDs

0

if you want a simple shell script for getting the maximum PID with variable, do this

pid=$(cat /proc/sys/kernel/pid_max)
echo $pid

that will print you the maximum PID can be.

SertseV
  • 5
  • 2
0

Portable way of achieving that

get_own_pid() {
  # This function being called in a subshell,
  # it must returns the pid of the parent of the "cut" command parent
  cut -d' ' -f4 < /proc/self/stat \
    | xargs -I% sh -c 'cut -d" " -f4 < /proc/%/stat'
}

get_parent_pid() {
  # Same thing but repeating the last command once more to get the parent one level above
  cut -d' ' -f4 < /proc/self/stat \
    | xargs -I% sh -c 'cut -d" " -f4 < /proc/%/stat' \
    | xargs -I% sh -c 'cut -d" " -f4 < /proc/%/stat'
}


# Here pid is the same as the $$ pid because called from main process
MY_PID=$(get_own_pid)
echo "$$ == ${MY_PID}"

# Here called in a subprocess, the returned pid is different
(
  MY_CHILD_PID=$(get_own_pid)
  PARENT_PID_FROM_CHILD=$(get_parent_pid)
  echo "$$ != ${MY_CHILD_PID}"
  echo "$$ == ${PARENT_PID_FROM_CHILD}"
)

Inspired from artem lapkin answer, thanks!

Antoine Laffargue
  • 2,276
  • 1
  • 8
  • 9