3

I'm new to shell,I just learned that use (command) will create a new subshell and exec the command, so I try to print the pid of father shell and subshell:

#!/bin/bash

echo $$
echo "`echo $$`"
sleep 4
var=$(echo $$;sleep 4)
echo $var

But the answer is:

$./test.sh
9098
9098
9098

My questions are:

  1. Why just three echo prints? There are 4 echos in my code.
  2. Why three pids are the same? subshell's pid is obviously not same with his father's.

Thanks a lot for answers :)

Coaku
  • 977
  • 1
  • 9
  • 23

3 Answers3

6

First, the assignment captures standard output of the child and puts it into var, rather than printing it:

var=$(echo $$;sleep 4)

This can be seen with:

$ xyzzy=$(echo hello)
$ echo $xyzzy
hello

Secondly, all those $$ variables are evaluated in the current shell which means they're turned into the current PID before any children start. The children see the PID that has already been generated. In other words, the children are executing echo 9098 rather than echo $$.

If you want the PID of the child, you have to prevent translation in the parent, such as by using single quotes:

bash -c 'echo $$'
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 1
    If you consult "man bash", the information in paxdiablo's answer is found under headings Command Substitution and Special Parameters. – minopret Apr 05 '12 at 06:45
  • I would add two things: 1. that there are *5* echos in the code, two of which are captured as strings (one echo'd immediately, the other stored in var). 2. In bash 4.0 and higher, the environment variable "$BASHPID" will print out the PID of the subshell. Bash 4.0 is not yet common, try bash --version to see yours. – Mike Apr 05 '12 at 06:47
0
echo "one.sh $$"
echo `eval echo '$$'`

I am expecting the above to print different pids, but it doesn't. It's creating a child process. Verified by adding sleep in ``.

echo "one.sh $$"
echo `eval "echo '$$'";sleep 10`

On executing the above from a script and running ps shows two processs one.sh(name of the script) and sleep.

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
test    12685  0.0  0.0   8720  1012 pts/15   S+   13:50   0:00      \_ bash one.sh
test    12686  0.0  0.0   8720   604 pts/15   S+   13:50   0:00          \_ bash one.sh
test    12687  0.0  0.0   3804   452 pts/15   S+   13:50   0:00              \_ sleep 10

This is the output produced

one.sh 12685
12685

Not sure what i am missing.

tuxuday
  • 2,977
  • 17
  • 18
  • Bash is sneaky, decides what `$$` expands to at startup and then keeps it in all the subshells it forks. (This is, as far as I know, intentional, to make the expansion stay the same, e.g., for naming temporary files.) – torek Apr 05 '12 at 08:39
  • [It's coz of this.](http://stackoverflow.com/questions/7858191/difference-between-bash-pid-and) – tuxuday Apr 05 '12 at 13:40
-1

The solution is $!. As in:

#!/bin/bash

echo "parent" $$
yes > /dev/null &
echo "child" $!

Output:

$ ./prueba.sh
parent 30207
child 30209