我正在后台从 bash 运行一个长期运行的管道:
find / -size +500M -name '*.txt' -mtime +90 |
xargs -n1 gzip -v9 &
由于存在多个大+旧文件,管道的第二阶段需要很长时间(数小时)才能完成。
相反,管道的第一部分立即完成,并且由于管道未满,并且它已完成,因此find
成功退出。
父bash
进程似乎wait
适合子进程。
我可以这么说,因为没有find
(pid 20851)根据以下任意一个运行:
ps alx | grep 20851
pgrep -l find
没有僵尸进程,也没有20851
在系统上的任何位置找到任何具有进程 ID 的进程。
bash 内置jobs
正确地将作业显示为单行,没有任何进程 ID:
[1]+ Running find / -size +500M -name '*.txt' -mtime +90 | xargs -n1 gzip -v9 &
OTOH:我偶然发现了一个单独的作业控制命令 ( /bin/jobs
),它显示:
[1]+ 20851 Running find / -size +500M -name '*.txt' -mtime +90
20852 Running | xargs -n1 gzip -v9 &
并且(错误地)将已经退出的20851
查找进程显示为“正在运行”。
这是在 CentOS(编辑:更准确地说:Amazon Linux 2 AMI
)Linux 上。事实证明这/bin/jobs
是一个两行/bin/sh
脚本:
#!/bin/sh
builtin jobs "$@"
这让我感到惊讶。从另一个程序 ( ) 启动的单独进程如何sh
知道由另一个程序 ( ) 管理的进程bash
在该进程已经完成并退出并且不是僵尸进程之后的详细信息?
pid
进一步:当系统上的其他方法(ps
、pgrep
)不能时,它如何知道有关已退出进程的详细信息(包括)?
编辑:
(1) 正如比利叔叔在评论中指出的那样,在这个系统上/bin/sh
和/bin/bash
是相同的(/bin/sh
是到 的符号链接/bin/bash
),但是/bin/jobs
是一个带有 shebang 行的脚本,因此它在单独的进程中运行。
(2) 另外,感谢比利叔叔:一种更简单的复制方法。/bin/jobs
这是一个转移注意力的话题。我错误地认为它是产生输出的那个。jobs
当使用以下命令调用时,令人惊讶的输出显然来自 bash 内置函数-l
:
$ sleep 1 | sleep 3600 &
[1] 13616
$ jobs -l
[1]+ 13615 Running sleep 1
13616 Running | sleep 3600 &
$ ls /proc/13615
ls: cannot access /proc/13615: No such file or directory
因此进程 13615 不存在,但由 bash 内置作业控制显示为“正在运行”,这看起来像是jobs -l
.
它的存在/bin/jobs
让我困惑,认为它一定是罪魁祸首(它不是),看起来令人困惑和可疑。我认为它应该从系统中删除,因为它是无用的(sh
在单独进程中运行的脚本,无论如何都无法显示调用者的作业)。
答案1
FWIW,我可以通过以下方式重现您的案例:
rhel8$ /bin/jobs(){ jobs -l; }
rhel8$ sleep 1 | sleep 3600 &
[1] 2611
rhel8$ sleep 2
rhel8$ jobs
[1]+ Running sleep 1 | sleep 3600 &
rhel8$ /bin/jobs
[1]+ 2610 Running sleep 1
2611 Running | sleep 3600 &
rhel8$ pgrep 2610
<nothing!>
rhel8$ ls /proc/2610
ls: cannot access '/proc/2610': No such file or directory
rhel8$ /bin/jobs
[1]+ 2610 Running sleep 1
2611 Running | sleep 3600 &
rhel8$ cat /bin/jobs
#!/bin/sh
builtin jobs "$@"
或者使用(甚至比以前更差):
rhel8$ unset -f /bin/jobs
rhel8$ export JOBS=$(jobs -l)
rhel8$ builtin(){ echo "$JOBS"; }
rhel8$ export -f builtin
rhel8$ /bin/jobs
[1]+ 2610 Running sleep 1
2611 Running | sleep 3600 &
rhel8$ type /bin/jobs
/bin/jobs is /bin/jobs
注意:正如已经演示的,jobs -l
在 bash 中显示的是过时的信息,已经退出的管道进程仍显示为Running
。恕我直言,这是一个错误 - 其他 shell(如 zsh、ksh 或 yash)正确地将它们显示为Done
.