raf*_*mag 99 linux unix bash process pid
我想启动进程(例如 myCommand)并获取它的 pid(以允许稍后杀死它)。
我试过 ps 并按名称过滤,但我无法按名称区分进程
myCommand
ps ux | awk '/<myCommand>/ {print $2}'
Run Code Online (Sandbox Code Playgroud)
因为进程名称不是唯一的。
我可以通过以下方式运行进程:
myCommand &
Run Code Online (Sandbox Code Playgroud)
我发现我可以通过以下方式获得这个 PID:
echo $!
Run Code Online (Sandbox Code Playgroud)
有没有更简单的解决方案?
我很乐意执行 myCommand 并通过一行命令获取其 PID。
Jac*_*zny 105
有什么比这更简单的echo $!?作为一行:
myCommand & echo $!
Run Code Online (Sandbox Code Playgroud)
Eli*_*gan 50
sh -c和exec获取命令的 PID 。要启动myCommand,以便在开始运行之前打印其 PID,您可以使用:
sh -c 'echo $$; exec myCommand'
Run Code Online (Sandbox Code Playgroud)
这将启动一个新的 shell,打印该 shell 的 PID,然后使用exec内置命令将 shell替换为您的命令,确保它具有相同的 PID。当您的 shell 运行带有exec内置命令的命令时,您的 shell实际上正在成为那个 command,而不是更常见的行为,即派生自己的新副本,它有自己单独的 PID,然后成为命令。
我发现这比涉及异步执行(使用&)、作业控制或使用 搜索的替代方案简单得多ps。这些方法很好,但除非您有使用它们的特定理由——例如,也许命令已经在运行,在这种情况下搜索其 PID 或使用作业控制是有意义的——我建议首先考虑这种方式。(我当然不会考虑编写复杂的脚本或其他程序来实现这一点)。
此答案包括此技术的示例。
即使您使用的 shell 是 Bourne 风格的,因此支持exec具有这些语义的内置程序,您通常也不应尝试避免使用sh -c(或等效的)为此目的创建一个新的、单独的shell 进程,因为:
myCommand,就没有 shell 等待运行后续命令。sh -c 'echo $$; exec myCommand; foo将foo自身替换为后将无法尝试运行myCommand。除非您正在编写一个将它作为最后一个命令运行的脚本,否则您不能只echo $$; exec myCommand在运行其他命令的 shell 中使用。(echo $$; exec myCommand)可能在语法上比 更好sh -c 'echo $$; exec myCommand',但是当你在$$里面运行时( ),它给出了父 shell 的 PID,而不是子 shell 本身的 PID。但是子shell的PID将成为新命令的PID。一些 shell 提供了它们自己的非便携式机制来查找子 shell 的 PID,您可以使用它。特别是,在 Bash 4 中,(echo $BASHPID; exec myCommand)确实有效。最后,请注意,某些 shell 将执行优化,在那里它们运行命令时就像通过exec(即,它们首先放弃分叉),当知道 shell 之后不需要做任何事情时。一些 shell 尝试在最后一个命令运行时执行此操作,而其他 shell 只会在该命令之前或之后没有其他命令时才执行此操作,而有些则根本不执行此操作。结果是,如果您忘记编写exec而只是使用,sh -c 'echo $$; myCommand'那么它有时会在某些具有某些外壳的系统上为您提供正确的 PID 。我建议不要依赖这种行为,而是始终包括exec你需要的时候。
use*_*517 30
将命令包装在一个小脚本中
#!/bin/bash
yourcommand &
echo $! >/path/to/pid.file
Run Code Online (Sandbox Code Playgroud)
我不知道有什么更简单的解决方案,但没有使用 $! 够好了?正如其他人所说,如果以后需要,您可以随时将值分配给其他变量。
作为旁注,您可以使用pgrepor代替来自 ps 的管道pidof。
将pid注册到文件后,使用bash脚本中的exec:
例子:
假设你有一个名为“forever.sh”的脚本,你想用参数 p1,p2,p3 运行它
永远.sh源代码:
#!/bin/sh
while [ 1 -lt 2 ] ; do
logger "$0 running with parameters \"$@\""
sleep 5
done
Run Code Online (Sandbox Code Playgroud)
创建一个收割者.sh:
#!/bin/sh
echo $$ > /var/run/$1.pid
exec "$@"
Run Code Online (Sandbox Code Playgroud)
通过reaper.sh运行forever.sh:
./reaper.sh ./forever.sh p1 p2 p3 p4 &
Run Code Online (Sandbox Code Playgroud)
forever.sh 只是每 5 秒记录一行到 syslog
您现在在 /var/run/forever.sh.pid 中有 pid
cat /var/run/forever.sh.pid
5780
Run Code Online (Sandbox Code Playgroud)
并且forever.sh 运行正常。系统日志grep:
Nov 24 16:07:17 pinkpony cia: ./forever.sh running with parameters "p1 p2 p3 p4"
Run Code Online (Sandbox Code Playgroud)
您可以在进程表中看到它:
ps axuwww|grep 'forever.sh p1' |grep -v grep
root 5780 0.0 0.0 4148 624 pts/7 S 16:07 0:00 /bin/sh ./forever.sh p1 p2 p3 p4
Run Code Online (Sandbox Code Playgroud)
在 bash shell 中,一个替代方法$!可能是jobs -p内置的。在某些情况下,!in$!在变量扩展之前(或代替)被 shell 解释,导致意外结果。
例如,这将不起作用:
((yourcommand) & echo $! >/var/run/pidfile)
Run Code Online (Sandbox Code Playgroud)
虽然这将:
((yourcommand) & jobs -p >/var/run/pidfile)
Run Code Online (Sandbox Code Playgroud)