On Wed, 2026-07-15 at 02:01 +0800, Wen Yang wrote:
> > Any better idea? We cannot really rely on the shell's $! because command
> > is using a combination of eval+timer and we'd get the wrong pid.
> >
>
> - Since $bgpid is the timeout process, its direct child is exactly the
> command we want. Using pgrep -P $bgpid avoids the fragile pattern
> matching of pgrep -f and won't accidentally match unrelated
> processes with a similar command string, eg:
>
> for i in $(seq 10); do
> pid=$(pgrep -P "$bgpid" | head -1)
> [ -n "$pid" ] && break
> sleep 0.5
> done
That would be neat, but apparently eval cmd & spawns a new shell (I'd assume to
keep control of the background task), so in practice we get something like:
bash(88148)───timeout(88150)───rv mon(88151)
while getting the pid of bash in $!, we could probably do:
pgrep -P "$(pgrep -P "$bgpid")"
but I'm not really sure how portable this is.
Now I tried all sorts of bash hacks but couldn't reliably avoid this subshell
(technically eval "cmd &" with quoted ampersand skips it, but breaks output
redirection or whatever else).
Unless you have a reliable way to get the pid that doesn't rely on some shell-
specific dark magic, I'd keep pgrep -f .
> Note: a bounded retry loop may be necessary; without an upper limit
> the loop hangs indefinitely if the command fails to exec.
>
> - For the verbose test specifically ("my pid is $pid"), the pid already
> appears in rv's own output. An alternative is to match it with a
> numeric pattern instead:
>
> "my pid is [0-9]\+"
>
> This sidesteps the race entirely for that test case.
Yeah an accurate pid isn't as important in that test, but since it seems to work
fine I'd keep it.
Thanks,
Gabriele