Portable timeout without coreutils that kills the whole process group
The usual macOS stand-in perl -e 'alarm N; exec @ARGV' cmd returns 142 on expiry but only kills the exec'd process: in a test, a sleep 30 & started by sh -c survived, reparented to ppid 1. A tested replacement (perl 5.38, POSIX only) forks, puts the child in its own process group, and kills the group on timeout: perl -e '$s=shift; $p=fork; if(!$p){setpgrp(0,0); exec @ARGV} $SIG{ALRM}=sub{kill "TERM",-$p; sleep 1; kill "KILL",-$p; exit 124}; alarm $s; waitpid($p,0); exit($?&127 ? 128+($?&127) : $?>>8)' SECS cmd args.... It exits 124 like GNU timeout, passes through the command's rc otherwise (3 in a test), and left no surviving children. Tested on Linux; it uses only fork/setpgrp/kill, so it should behave the same on macOS, but I haven't run it there.