如何使用 ps aux 正确检索与 Java 相关的进程的 PID?以及如何放置包含输出列名的 header?

如何使用 ps aux 正确检索与 Java 相关的进程的 PID?以及如何放置包含输出列名的 header?

我不是系统管理员(我是软件开发人员),我有以下疑问。

执行此命令,我可以看到系统上运行的前 10 个进程的列表(如果我做错了,请纠正我):

[email protected] [~/FOLDER]# ps aux | head -10
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0 191292  3892 ?        Ss    2021  21:29 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
root         2  0.0  0.0      0     0 ?        S     2021   0:00 [kthreadd]
root         4  0.0  0.0      0     0 ?        S<    2021   0:00 [kworker/0:0H]
root         6  0.0  0.0      0     0 ?        S     2021   2:17 [ksoftirqd/0]
root         7  0.0  0.0      0     0 ?        S     2021   0:10 [migration/0]
root         8  0.0  0.0      0     0 ?        S     2021   0:00 [rcu_bh]
root         9  0.1  0.0      0     0 ?        S     2021  71:37 [rcu_sched]
root        10  0.0  0.0      0     0 ?        S<    2021   0:00 [lru-add-drain]
root        11  0.0  0.0      0     0 ?        S     2021   0:56 [watchdog/0]

所以第二列是PID识别进程(我可以用它来终止一个进程)。

然后我尝试执行此命令来检索与爪哇

[email protected] [~/FOLDER]# ps aux | grep java
webadmin 22316  0.0  0.0 112812   980 pts/0    S+   18:21   0:00 grep --color=auto java

基本上我只过滤与 java 相关的行

这里有一个疑问。PID始终是第二列的值吗?

是否可以像第一个代码片段中那样放置包含列名的标题?

答案1

简短的回答是你不需要使用ps aux它。

通常这样的过程将运行为服务,以及服务管理器跟踪的它们的 PID(例如 systemd;Upstart;supervisord;Monit……)如果目标是检查服务是否正在运行 – 服务管理器可以回答这个问题。(例如,systemctl is-active MyApp)如果目标是在服务崩溃时重新启动服务,或者防止服务运行两次 – 服务管理器的工作就是这样做。

在进程无法作为服务运行的情况下,应在启动时立即记录其 PID到 PID 文件– 应用程序本身或启动器都可以执行此操作。(例如,java -jar myapp.jar & echo $! > java.pid。)

当您确实需要搜索所有正在运行的进程时,请使用该pgrep命令。例如,要查找所有 Java 进程,请使用pgrep java,要查找所有提及 MyApp.jar 的进程,请使用pgrep -f MyApp.jar。(添加选项-a以查看命令,例如pgrep -a java。)这样就不会出现像 grep 那样返回其本身的问题ps|grep

如果你一定要使用ps,那么指定确切的列您想要的。现在该u选项已经要求特定的格式,特定的列以特定的顺序排列——但如果您想要的只是 PID,该o选项只允许您获取 PID。例如,ps axo pid,cmd总是会得到两列:PID 和命令,按该顺序排列。

答案2

仅查找 PIDpgrep通常比 更好ps

现在我假设你知道你想要什么,你真正想要什么ps,你想要标题。这个特定的任务可以用以下方法完成sed

ps aux | sed -n '1p; /java/p'

请注意,您ps … | grep …可能会找到grep本身。类似地,我的命令会找到sed。您可以通过使用等同于java但不包含 的正则表达式来避免这种情况java。示例:

ps aux | sed -n '1p; /[j]ava/p'

如果您愿意grep(例如因为它能够添加颜色),则以下方法似乎应该有效:

# flawed though, don't use it
ps aux | { head -n 1; grep '[j]ava'; }

它的缺陷在于head可能会读取太多,并且没有办法将过度消耗的数据放回去以供grep读取。read在这方面更好,它一次读取一个字符,因此它可以可靠地读取一行:

ps aux | (IFS= read -r line; printf '%s\n' "$line"; grep '[j]ava')

注意,我强制使用子 shell,因此变量随之消亡,而主 shell 不受影响*。


* Shell 可以在不在子 Shell 中或隐式地在子 Shell 中运行管道的最后一部分。read line不在子 Shell 中将line在主 Shell 中设置变量。如果变量已经存在并且包含重要值怎么办?通过强制子 Shell,我们可以保护主 Shell 的状态,无论主 Shell 如何运行。

相关内容