bash 获取后台进程 id 给出父 pid
bash getting background process id gives parent pid
使用此命令创建 bash 脚本:
cat <<"END"> z
#! /bin/bash
sleep 20 && exit 1 &
ret=$!
ps $ret | grep $ret
END
然后 运行 它给出:
7230 pts/39 S+ 0:00 /bin/bash ./z
我期待看到 sleep 20 ...
这是子进程。如果我删除 && exit 1
它会 return 子进程。
这是什么原因?如何获取上述语句中的子进程 ID?
你看到的不是父pid,而是子shell pid
当你 运行 :
sleep 20 && exit 1 &
进程树如下:
current-shell ---> sub-shell ---> 'sleep 20 && exit 1'
当你 运行 :
sleep 20 &
进程树如下:
current-shell ---> 'sleep 20'
您看到 'sleep 20'
的 pid 的原因
Whats the reason?
原因是某些实体必须做 &&
。不可能是sleep
,因为sleep
只是休眠,在sleep
终止后(所以不再有sleep
做任何决定),一些"entity"需要比较sleep
的退出状态,决定再执行exit 1
。 "entity" 是 shell,必须是 "above" sleep
才能执行操作。所以 "real" 后台进程是 shell,sleep
是它的子进程。
在只有 sleep 20 &
的情况下,在 bash 中有一个优化,父 shell 在 bash 的情况下看到只有一个命令要做。所以 bash 扫描整个 command command bla bla &
并发现只有一个命令要做。因此 bash 只调用 exec
而不是标准的 fork+exec
并成为 sleep
本身而不是 运行 子进程。因为 exec
subshell 变成了 sleep
,所以你可以在进程名称中看到它。这是完成的资源优化 bash.
您已经获得了有关子进程的正确信息。只有在您的情况下,ps
不知道或不想为您在后台启动的链式子流程显示正确的 COMMAND
名称 - 这可能让您感到困惑。
看起来这是链式命令的情况(.. && ...
,因此它与 exit 1
无关,也可能是 echo 5
等),其中 process group leader 名称显示为 cmd
名称。
来自 (ps man page)
`cmd | COMMAND`: simple name of executable
# Process state codes
`S`: interruptible sleep (waiting for an event to complete)
`+`: is in the foreground process group
查看 ps | grep
输出中的 S+
。
因此,您可以稍微调整一下脚本以确认您确实捕获了 (d) 有关子进程的正确信息,如下所示:
cat <<"END"> z
#! /bin/bash
sleep 20 && exit 1 &
ret=$!
echo $ret
jobs -l
# display parent and child process info
# -j Jobs format
ps -j $$ $ret
END
echo $ret
的输出:
30274
jobs -l
的输出:
[1]+ 30274 Running sleep 20 && exit 1 &
ps -j $$ $ret
的输出:
PID PGID SID TTY STAT TIME COMMAND
30273 30273 21804 pts/0 S+ 0:00 /bin/bash ./z
30274 30273 21804 pts/0 S+ 0:00 /bin/bash ./z
注意父子进程都是一样的PGID
,而jobs -l
和[=31]显示的子进程的pid是30274 =] 匹配。
此外,如果您将 sleep 20 && exit 1 &
更改为 bash -c 'sleep 20 && exit 1' &
,这次您将获得一个正确的子命令名称,如下所示(参见上面的输出顺序):
30384
[1]+ 30384 Running bash -c 'sleep 20 && exit 1' &
PID PGID SID TTY STAT TIME COMMAND
30383 30383 21804 pts/0 S+ 0:00 /bin/bash ./z
30384 30383 21804 pts/0 S+ 0:00 bash -c sleep 20 && exit 1
最后但同样重要的是,在你的原始版本中你也可以尝试
而不是 ps $ret | grep $ret
pstree -s $ret
-s: Show parent processes of the specified process.
这将为您提供类似于下面的输出,这也将确认您获得了 sleep 20 && exit 1 &
:
的正确过程信息
systemd───systemd───gnome-terminal-───bash───bash───sleep
使用此命令创建 bash 脚本:
cat <<"END"> z
#! /bin/bash
sleep 20 && exit 1 &
ret=$!
ps $ret | grep $ret
END
然后 运行 它给出:
7230 pts/39 S+ 0:00 /bin/bash ./z
我期待看到 sleep 20 ...
这是子进程。如果我删除 && exit 1
它会 return 子进程。
这是什么原因?如何获取上述语句中的子进程 ID?
你看到的不是父pid,而是子shell pid
当你 运行 :
sleep 20 && exit 1 &
进程树如下:
current-shell ---> sub-shell ---> 'sleep 20 && exit 1'
当你 运行 :
sleep 20 &
进程树如下:
current-shell ---> 'sleep 20'
您看到 'sleep 20'
的 pid 的原因Whats the reason?
原因是某些实体必须做 &&
。不可能是sleep
,因为sleep
只是休眠,在sleep
终止后(所以不再有sleep
做任何决定),一些"entity"需要比较sleep
的退出状态,决定再执行exit 1
。 "entity" 是 shell,必须是 "above" sleep
才能执行操作。所以 "real" 后台进程是 shell,sleep
是它的子进程。
在只有 sleep 20 &
的情况下,在 bash 中有一个优化,父 shell 在 bash 的情况下看到只有一个命令要做。所以 bash 扫描整个 command command bla bla &
并发现只有一个命令要做。因此 bash 只调用 exec
而不是标准的 fork+exec
并成为 sleep
本身而不是 运行 子进程。因为 exec
subshell 变成了 sleep
,所以你可以在进程名称中看到它。这是完成的资源优化 bash.
您已经获得了有关子进程的正确信息。只有在您的情况下,ps
不知道或不想为您在后台启动的链式子流程显示正确的 COMMAND
名称 - 这可能让您感到困惑。
看起来这是链式命令的情况(.. && ...
,因此它与 exit 1
无关,也可能是 echo 5
等),其中 process group leader 名称显示为 cmd
名称。
来自 (ps man page)
`cmd | COMMAND`: simple name of executable
# Process state codes
`S`: interruptible sleep (waiting for an event to complete)
`+`: is in the foreground process group
查看 ps | grep
输出中的 S+
。
因此,您可以稍微调整一下脚本以确认您确实捕获了 (d) 有关子进程的正确信息,如下所示:
cat <<"END"> z
#! /bin/bash
sleep 20 && exit 1 &
ret=$!
echo $ret
jobs -l
# display parent and child process info
# -j Jobs format
ps -j $$ $ret
END
echo $ret
的输出:
30274
jobs -l
的输出:
[1]+ 30274 Running sleep 20 && exit 1 &
ps -j $$ $ret
的输出:
PID PGID SID TTY STAT TIME COMMAND
30273 30273 21804 pts/0 S+ 0:00 /bin/bash ./z
30274 30273 21804 pts/0 S+ 0:00 /bin/bash ./z
注意父子进程都是一样的PGID
,而jobs -l
和[=31]显示的子进程的pid是30274 =] 匹配。
此外,如果您将 sleep 20 && exit 1 &
更改为 bash -c 'sleep 20 && exit 1' &
,这次您将获得一个正确的子命令名称,如下所示(参见上面的输出顺序):
30384
[1]+ 30384 Running bash -c 'sleep 20 && exit 1' &
PID PGID SID TTY STAT TIME COMMAND
30383 30383 21804 pts/0 S+ 0:00 /bin/bash ./z
30384 30383 21804 pts/0 S+ 0:00 bash -c sleep 20 && exit 1
最后但同样重要的是,在你的原始版本中你也可以尝试
而不是ps $ret | grep $ret
pstree -s $ret
-s: Show parent processes of the specified process.
这将为您提供类似于下面的输出,这也将确认您获得了 sleep 20 && exit 1 &
:
systemd───systemd───gnome-terminal-───bash───bash───sleep