0

I am trying to get the pid of the previous command with $!, but that only works in the 'main' shell:

$ echo "test" | echo $!
4436
$

If I start a subshell, then it's empty:

$ bash
$ echo "test" | echo $!

$

If I run it with -c, the same happens:

$ bash -c 'echo "test" | echo $!'

$

Can I rewrite something, or add options to make this work with bash -c?

  • $! Expands to the process ID of the job most recently placed into the background. The PID you are seeing is from way back (possibly when the shell was initialising, and not from any command of yours). echo is a shell built-in, so it does not even start a separate process. – Paul_Pedant Jun 19 '20 at 09:45

2 Answers2

2

$! will hold the PID of the most recently started background job (a command ending with &). You can't use it in the ways you show to get information about other parts of the pipeline.

The fact that your pipeline echo "test" | echo $! outputs a number only means that you started a background job at some point previous to running the pipeline. The number outputted has nothing to do with anything in your pipeline. In a fresh shell, where no background jobs have been started, that pipeline would output nothing.

Kusalananda
  • 333,661
  • @Kusalanandawould a process list capture a pid from a command? e.g. (pwd ; echo $$) – summertime Jun 19 '20 at 10:00
  • 1
    @summertime The echo in (pwd ; echo $$) would output the PID of the shell executing the subshell. The echo in (echo "$BASH_PID") would output the PID of the subshell. It's unclear what you are trying to do. – Kusalananda Jun 19 '20 at 10:13
  • I was just asking for general knowledge. Thanks! – summertime Jun 19 '20 at 10:20
1

$! is the PID of the job that this shell last placed into the background. If you want to do anything with it, you should usually save it to a variable, since running another background process will overwrite it. $! is like $? in this respect, although it doesn't get overwritten nearly as quickly.

Like with any other variable, if you want to make it available to a child process, export it to the environment.

background_command &
export background_command_pid=$!
…
bash -c 'echo "My background sibling process is $background_command_pid"'

By the way, contrary to your assertion, $! is preserved in subshells.

$ sleep 3 & echo $!
23791
$ { echo $! | cat; }                           
23791
$ ( echo $!; /bin/cat /dev/null; ); /bin/cat /dev/null
23791
$ echo $! $(echo $!)
23791 23791

Running another instance of bash is not a subshell. You're confusing a subshell with a child process that is a shell.