我正在编写一个 bash 脚本的包装应用程序,并希望应用程序跟踪从用户脚本启动了哪些工具/进程。我想知道确定生成的子进程列表的最佳方法是什么这父进程。
我试过
- 定期调用附注命令并构建进程树(如 ps -ejH),但这会错过快速运行完成的进程。
- 使用类似的工具福克斯塔它使用 proc 连接器接口,但只能以提升的权限运行。虽然这给出了正确的数据,但以 sudo 身份运行在我的情况下不起作用?
有什么建议可以实现这一点吗?
答案1
如果您使用的是 Linux,则可以使用strace
来跟踪进程使用的系统调用。例如:
~ strace -e fork,vfork,clone,execve -fb execve -o log ./foo.sh
foo bar
~ cat log
4817 execve("./foo.sh", ["./foo.sh"], [/* 42 vars */]) = 0
4817 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f1bb563b9d0) = 4818
4818 execve("/bin/true", ["/bin/true"], [/* 42 vars */] <detached ...>
4817 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=4818, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
4817 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f1bb563b9d0) = 4819
4817 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f1bb563b9d0) = 4820
4820 execve("/bin/echo", ["/bin/echo", "foo", "bar"], [/* 42 vars */] <detached ...>
4817 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=4820, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
4817 +++ exited with 0 +++
4819 execve("/bin/sleep", ["sleep", "1"], [/* 42 vars */] <detached ...>
您可以看到该脚本使用系统调用分叉了三个进程(PID 4818、4819、4820)clone(2)
,并且execve(2)
这些分叉进程中的系统调用显示了执行的命令。
-e fork,vfork,clone,execve
将 strace 输出限制为这些系统调用-f
跟随子进程-b execve
当达到 时从进程分离execve
,因此我们看不到子进程的进一步跟踪。
答案2
pstree -p `pgrep NetworkManager`
NetworkManager(1638)─┬─dhclient(3594)
├─{NetworkManager}(1645)
├─{NetworkManager}(1647)
└─{NetworkManager}(7363)
我想这就是你正在寻找的。
使用直接 pid 或 pgrep 和进程名称。
-p 用于打印子进程的 pid。
答案3
程序包命令会有帮助。使用这些命令:
从 process( ) 打印每个分叉进程的 PID $pid
:
pgrep -P $pid
有关每个分叉进程的更多详细信息,请使用以下命令:
ps -fp `pgrep -P $pid`
$pid
你的进程 ID 在哪里。
答案4
我想知道确定该父进程生成的子进程列表的最佳方法是什么。
假设你是用bash写的(你没有说)。然后您可以使用作业控制。运行脚本时,默认情况下此功能处于关闭状态。
bash 手册说:
设置 [--abefhkmnptuvxBCHP] [-o 选项] [arg ...]
...
-m 监视模式。
作业控制已启用。对于支持它的系统上的交互式 shell,此选项默认处于启用状态(请参阅上面的作业控制)。后台进程在单独的进程组中运行,并在完成时打印包含其退出状态的行。
因此,添加到您的脚本中set -m
,您可以使用 启动命令,command &
然后使用jobs
来列出作业。