3

Say I run time ./a.out, then I can get the PID of time by the variable $!. But how do I get the PID of a.out?

Of course, I could parse the output of ps, but I want a more elegant solution.

I've checked man time and couldn't find anything.

The closest I've gotten is time (sleep 10 & echo $!), but because of the fork, the time taken is basically 0 and not 10s as it should be.

  • 1
    Add a wait to the end of your subshell and you'll get the "right" answer: time (sleep 10 & echo $!; wait). Or see my suggested Answer for a slightly more sophisticated suggestion – roaima Mar 13 '15 at 22:37
2

By definition, a.out is a child process of time. So time is the parent pid of a.out! here's a test where I replace a.out with sleep 60:

$ time sleep 50 & timepid=$!
$ aoutpid=$(pgrep -P $timepid)
$ ps -o ppid,pid,start,cmd w -p $$,$timepid,$aoutpid

PPID   PID  STARTED CMD
2065  2068 21:34:57 -bash
2068  3297 22:16:05 -bash
3297  3298 22:16:05 sleep 50

(note: where time is actually a shell build-in, so the command above is bash!)

2

If the time to start a shell is negligible compared to the time it takes to run the command, you can run an intermediate shell, and use the exec builtin to ensure that a.out replaces the shell rather than being executed as a subprocess.

time sh -c 'echo $$; exec ./a.out'
1

Try pgrep to find the PID:

pgrep -l "a.out"

Read map pgrep to get more idea.

  • Thanks, but I was looking for a more direct method that would guarantee an accurate pid. If there are multiple processes named a.out there would be an ambiguity – texasflood Mar 13 '15 at 18:59
  • @texasflood: How about pgrep "a.out" | xargs ps -fp? – heemayl Mar 13 '15 at 19:08
  • That doesn't seem to work. If I run sleep 200 in two different terminals, pgrep "sleep" | xargs ps -fp gets both. Of course I may be making a mistake. What I want is to guarantee I only get the pid of the process I run with time, not any other processes with the same name – texasflood Mar 13 '15 at 19:12
  • @texasflood: You are right but you have all info like PPID, STIME, TTY to easily differentiate between two.. – heemayl Mar 13 '15 at 19:15
  • That's true, and that would work most of the time, but it doesn't scale well. It's also more involved. There may be multiple processes with the same name running in the same TTY and processes may be starting concurrently from different threads within the same TTY. It is possible to construct a scenario in which it is practically impossible to differentiate two processes. – texasflood Mar 13 '15 at 19:20
1

Job control lets you put it in the background and get it back in foreground again:

time ( set -m; sleep 10 & echo $! ; fg >/dev/null ; )

Hmm … the complete command winds up as a stopped job, though. Odd. Here's a workaround:

bash -c ' time ( set -m; sleep 10 & echo $! ; fg >/dev/null ; ) '

Of course, by then it might as well be:

bash -c ' time { set -m; sleep 10 & echo $! ; fg >/dev/null ; } '

I'd prefer avoiding that bash -c, but I'm kinda fresh out of ideas. :-\

ETA: Of course, if you don't have job control enabled in your shell, the first version works. If you do have job control enabled in your shell, you can turn it off first, and on again afterwards:

set +m; time ( set -m; sleep 10 & echo $! ; fg >/dev/null ; ) ; set -m

But for the general case, where the shell may or may not have job control enabled? Check for monitor in $SHELLOPTS and pick one?

1

It's possible by writing a small shell fragment that runs the remainder of its command line as a child process, capturing that child's PID as a side-effect.

Here's a script that will do that for you (error checking omitted for brevity)

#!/bin/sh
#
"$@" &
CHILD=$!
echo "$CHILD" >/tmp/mychild.pid
echo "INFO: child is $CHILD" >&2
wait

If you were to name it whatsmychild then you would use it in your scenario like this:

time whatsmychild a.out

Evidence that it works? Here is another scriptlet; let's call this one whatsmypid:

#!/bin/sh
#
echo "My PID is $$" >&2
exit 0

Now we'll run it:

$ time identifymychild whatsmypid
INFO: child is 8105
My PID is 8105

real    0m0.006s
user    0m0.000s
sys     0m0.000s
$ cat /tmp/mychild.pid
8105

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.