我需要检索一个进程的 PID,该进程通过管道传输到另一个进程,这些进程一起作为 bash 中的后台作业生成。以前我只是简单地依赖pgrep
,但事实证明,在pgrep
找到进程之前可能会有 >2 秒的延迟:
#!/bin/bash
cmd1 | cmd2 &
pid=$(pgrep cmd1) # emtpy in about 1/10
我发现针对此问题的一些常见建议是使用进程替换而不是简单的管道 ( cmd1 >(cmd2) & pid=$!
) 或使用jobs
内置函数。进程替换运行整个子shell(对于整个运行时),所以我宁愿jobs
现在使用,但我想避免两次犯同样的错误......
如果我在生成两个进程后立即执行查找,我是否可以 100% 依赖于jobs
了解这两个进程?
#!/bin/bash
cmd1 | cmd2 &
pid=$(jobs -p %cmd1) # 10/10?
这可能是由于在后台运行作业,或者可能是一个怪癖set -x
,但以下示例通常以任意顺序列出执行的命令。输出jobs
出现到目前为止是正确的,但我想完全排除可能jobs
被执行的可能性前作业已经启动(或者至少jobs
无法列出两个进程)!?
#!/bin/bash
set -x
tail -f /dev/null | cat &
jobs -l
kill %tail
例子:
+ jobs -l
[1]+ 2802325 Running tail -f /dev/null
2802326 | cat &
+ tail -f /dev/null
+ kill %tail
同样,在流程替换的情况下,我可以依赖pid=$!
始终工作吗?它到底被设计为“扩展到最近执行的后台(异步)命令的进程ID”?
答案1
当后台作业是表单的管道时cmd1 | cmd2
,它仍然是单个后台作业。没有办法知道什么时候cmd1
开始。
每个&
都会创建一个后台作业。一旦cmd &
返回,shell 就会知道该后台作业:cmd & jobs
lists cmd
。cmd & pid=$!
设置pid
为运行的进程 ID cmd
。
该管道cmd1 | cmd2
创建了另外两个子进程:一个 to run cmd1
,一个 to run cmd2
。这两个进程都是运行后台作业的子进程的子进程。以下是进程树的样子bash -c '{ sleep 123 | sleep 456; } & jobs -p; sleep 789'
:
PID PPID CMD
268 265 | \_ bash -c { sleep 123 | sleep 456; } & sleep 789
269 268 | \_ bash -c { sleep 123 | sleep 456; } & sleep 789
270 269 | | \_ sleep 123
271 269 | | \_ sleep 456
272 268 | \_ sleep 789
268是原始的bash进程。 269 是打印的后台作业jobs -p
。 270 和 271 是管道的左侧和右侧,都是后台作业 (269) 主进程的子进程。
我测试的 bash 版本(Linux 上为 5.0.17)cmd1 | cmd2 &
在没有大括号的情况下进行了优化。在这种情况下,管道的左侧与后台作业在同一进程中运行:
PID PPID CMD
392 389 | \_ bash -c sleep 123 | sleep 456 & jobs -p; sleep 789
393 392 | \_ sleep 123
394 392 | \_ sleep 456
395 392 | \_ sleep 789
您不能依赖此行为在 bash 版本之间保持稳定,甚至可能在平台、发行版、libc 版本等之间保持稳定。
jobs -p %cmd1
寻找代码以 开头的工作cmd1
。它发现的是cmd1 | cmd2
.jobs -p %?cmd2
找到同样的工作。无法通过 bash 的内置功能cmd1
访问正在运行的进程 ID。cmd2
如果您需要确定是否cmd1
已启动,请使用进程替换。
cmd1 >(cmd2)
你不知道什么时候cmd2
开始和结束。
如果您需要知道何时开始cmd1
和cmd2
结束,则需要使它们同时工作,并让它们通过命名管道进行通信。
tmp=$(mktemp -d) # Remove this in cleanup code
mkfifo "$tmp/pipe"
cmd1 >"$tmp/pipe" & pid1=$!
cmd2 <"$tmp/pipe" & pid2=$!
…
该jobs
命令在脚本中不是很有用。用于$!
记住后台作业的 PID。
1或者至少应该如此。我的版本抱怨工作规范不明确,这一定是一个错误,因为它说尽管只有一个工作。