I am currently starting a background process within a subshell and was wondering how can I assign its pid number to a variable outside the subshell scope?
I have tried many different ways but MYPID always stays set to 0.

MYPID = 0;
({ sleep 2 & }; $MYPID=$!)
({ sleep 2 & }; echo $!) > $MYPID

The only way it returns a value is with:

$MYPID=$({ sleep 2 & }; echo $!)

However this discards the background process instruction and it will only return a result after 2 seconds.

  • 1
    What exactly are you trying to achieve? Why not simply sleep 2 & mypid=$!? Sep 24, 2014 at 13:56
  • I am trying to suppress the process creation stdout. Both start showing the PID address and final with Done confirmation.
    – zanona
    Sep 24, 2014 at 14:08

2 Answers 2


bash shouldn't print the job status when non-interactive.

If that's indeed for an interactive bash, you can do:

{ pid=$(sleep 20 >&3 3>&- & echo "$!"); } 3>&1

We want sleep's stdout to go to where it was before, not the pipe that feeds the $pid variable. So we save the outer stdout in the file descriptor 3 (3>&1) and restore it for sleep inside the command substitution. So pid=$(...) returns as soon as echo terminates because there's nothing left with an open file descriptor to the pipe that feeds $pid.

However note that because it's started from a subshell (here in a command substitution), that sleep will not run in a separate process group. So it's not the same as running sleep 20 & with regards to I/O to the terminal for instance.

Maybe better would be to use a shell that supports spawning disowned background jobs like zsh where you can do:

sleep 20 &! pid=$!

With bash, you can approximate it with:

{ sleep 20 2>&3 3>&- & } 3>&2 2> /dev/null; pid=$!; disown "$pid"

bash outputs the [1] 21578 to stderr. So again, we save stderr before redirecting to /dev/null, and restore it for the sleep command. That way, the [1] 21578 goes to /dev/null but sleep's stderr goes as usual.

If you're going to redirect everything to /dev/null anyway, you can simply do:

{ apt-get update & } > /dev/null 2>&1; pid=$!; disown "$pid"

To redirect only stdout:

{ apt-get-update 2>&3 3>&- & } 3>&2 > /dev/null 2>&1; pid=$!; disown "$pid"
  • That looks great Stéphane. Thanks for that. I really liked the way you delegate outputs there. Would you mind explaining in the answer what each part is doing please? As I am learning this would be a valuable asset :) Thanks again
    – zanona
    Sep 24, 2014 at 14:42
  • Sounds great, is it possible however to omit the output (except errors for the command in question) supposing I use apt-get update instead sleep I usually would send that to > /dev/null however since it is sending ’2>&3 the output still showing?
    – zanona
    Sep 24, 2014 at 14:49
  • That’s marvellous Stéphane. thanks so much for the thorough explanation. The only thing is that on the last example with the apt-get update unfortunately when there is an error it won’t be logged since it is simple discarding everything. I was wondering about a way to keep the errors and discard the rest, however, I am not sure if that is possible. But I just noted that the process output [1] 23929 is sent to stderr so I believe this is a tricky thing :) Thanks once again for your help.
    – zanona
    Sep 24, 2014 at 15:24
  • Thanks for the thorough explanations and in particular for the emulation of spawning disowned background jobs. Nov 17, 2014 at 17:06
  • For those of you wondering: 3>&- closes fd 3 in the end (the innermost part of the code). With the preceding 2>&3, it's essentially a move of fd 3 to 2, which could also be written as 2>&3- (see gnu.org/software/bash/manual/bash.html#Moving-File-Descriptors). Feb 10 at 17:42

second line can't work

({ sleep 2 & }; $MYPID=$!)

the ( ... ) fork a subshell, MYPID is set, then subshell exit and it's value is lost.

third line didn't work either

({ sleep 2 & }; echo $!) > $MYPID

you just echo $! to a file named 0 on local dir.

The only answer I can provide is via a temporary file (as var can't be push back)

 ( { sleep 100 & } ; echo $! > u ) > /dev/null &> /dev/null

you can replace u with any file.

  • Sounds good Archemar, I am using this process so far. However, I am not sure if there is a correct way to set temporary files? I am not sure if using mktemp or > /tmp/file Also what would be the best procedure after getting the PID? Should I remove the temporary file?
    – zanona
    Sep 24, 2014 at 14:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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