更加优雅的 "ps aux | grep -v grep"

191

当我检查进程列表并使用“grep”筛选出对我有意义的进程时,grep本身也包含在结果中。例如,列出终端:

当我检查进程列表并使用“grep”筛选出对我有意义的进程时,结果中也会包括grep本身。例如,要列出终端:

$ ps aux  | grep terminal
user  2064  0.0  0.6 181452 26460 ?        Sl   Feb13   5:41 gnome-terminal --working-directory=..
user  2979  0.0  0.0   4192   796 pts/3    S+   11:07   0:00 grep --color=auto terminal

通常我使用ps aux | grep something | grep -v grep来消除最后一条记录... 但这并不是优雅的方式 :)

你有一个更优雅的方法解决这个问题吗(除了把所有命令都包装成一个单独的脚本,这也不错)


4
就此而言,这是一个古老的常见问题解答(FAQ)。请参见http://www.faqs.org/faqs/unix-faq/faq/part3/中的第3.10条目。 - tripleee
1
感谢提供参考。这是他们的方法:ps ux | awk '/name/ && !/awk/ {print $2}' - Jakub M.
grep -v grep”这部分是在做什么? - Jwan622
2
@Jwan622 grep -v grep 可以从 grep 结果中排除 grep。如果将 grep 与 ps 结合使用,则 grep 进程(带有 grep 参数)也会显示出来,使结果混乱。grep -v grep 是避免这种情况的常见方法。 - Eugene Platonov
9个回答

291
通常的技术是这样的:
ps aux | egrep '[t]erminal'

这将匹配包含“terminal”的行,而“egrep '[t]erminal'”则不会!它还适用于许多版本的Unix。

1
这对于任意字符串都适用,但对于用户名(例如 ps aux | grep '[r]oot')则不适用。有人知道为什么吗? - kxsong
2
@kxsong: | grep '[t]erminal' 选择包含单词“terminal”的任何行,而不将单词“terminal”放入进程列表中。你尝试使用 | grep '[r]oot' 做什么?为什么它不起作用?可能有更好的解决方案。 - johnsyweb
3
如有错误,请纠正我,但这个命令对于所搜索的字符出现在任何位置都应该有效:ps aux| grep "te[r]minal"。 - meso_2600
2
闪光的黑客技巧(我认为我应该这样称呼它,因为aux/grep的作者可能没有考虑到这种情况。) - Michahell
2
@JamieJag:嗯...就像我在帖子中说的那样,grep '[t]erminal'将匹配包含“terminal”的行。从ps aux输出的结果中会有一行包含grep '[t]erminal'(带有方括号),但不包含字符串terminal(没有方括号)。 - johnsyweb
显示剩余2条评论

60

12
pgrep -f 是什么意思? - hillu
4
默认情况下,pgrep 只会匹配进程的名称。若要匹配整个命令,则需使用 -f 标志。 - bluecollarcoder
3
pgrep 只返回进程 ID。 - Melab
@Melab 不,你可以使用 pgrep -a 获取完整的命令行。 - Desty
1
旧版本使用 pgrep -fl 命令(但是没有 -f 选项无法查看完整的命令行,详情请参考:https://serverfault.com/a/619788/44183)。但是如果您需要 pid、cmdline 以外的其他信息,您需要使用 ps 命令。可以将它们组合起来使用:ps -p $(pgrep -f foo) - Beni Cherniavsky-Paskin
显示剩余5条评论

29

本答案是在之前的 pgrep 答案 的基础上建立的。它还借鉴了另一个答案,结合使用pspgrep。以下是一些相关的训练示例:

$ pgrep -lf sshd
1902 sshd

$ pgrep -f sshd
1902

$ ps up $(pgrep -f sshd)
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root      1902  0.0  0.1  82560  3580 ?        Ss   Oct20   0:00 /usr/sbin/sshd -D

$ ps up $(pgrep -f sshddd)
error: list of process IDs must follow p
[stderr output truncated]

$ ps up $(pgrep -f sshddd) 2>&-
[no output]

上述内容可以用作一个函数:

$ psgrep() { ps up $(pgrep -f $@) 2>&-; }

$ psgrep sshd
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root      1902  0.0  0.1  82560  3580 ?        Ss   Oct20   0:00 /usr/sbin/sshd -D

与使用psgrep相比较。有用的标题行不会被打印出来。
$  ps aux | grep [s]shd
root      1902  0.0  0.1  82560  3580 ?        Ss   Oct20   0:00 /usr/sbin/sshd -D

请参见 https://github.com/blueyed/oh-my-zsh/blob/a08181210b47625efdc8480e628b0155bff392c9/lib/aliases.zsh#L10-L18(但它只适用于Zsh)。 - blueyed
@blueyed,我已经更新了答案,并加入了Bash函数定义。 - Asclepius
请注意,还有一个-d选项可用于指定分隔符,例如:ps -fp$(pgrep -d , getty) - Toby Speight
1
我使用这个命令:ps uxp `pgrep <process>` 请注意,p 必须是最后一个参数(即 pux 不起作用)。 - KFL
这不像grep那样给搜索进程命名颜色。 - alper

10

您可以使用ps命令进行筛选,例如:

ps u -C gnome-terminal

(或使用find等在/ proc中搜索。)


1
请注意,这适用于GNU的ps(Linux),但不适用于BSD ps。 - Josh
即使使用GNU ps也是不正确的。ps -C <command>将匹配完全相同的命令。当与ax选项一起使用时,它将报告所有进程,因为ax列出了除其他方式匹配的进程集之外的进程。 - Animism
@Animism 是的。谢谢,我已经修复了。 - Andreas Frische
只有在进程名称完全指定的情况下才能正常工作。它无法处理部分匹配,例如将 logindsystemd-logind 匹配,或者匹配参数。 - Asclepius

6

另一个选择

ps -fC terminal

以下是选项:

 -f        does full-format listing. This option can be combined
           with many other UNIX-style options to add additional
           columns. It also causes the command arguments to be
           printed. When used with -L, the NLWP (number of
           threads) and LWP (thread ID) columns will be added. See
           the c option, the format keyword args, and the format
           keyword comm.

 -C cmdlist     Select by command name.
                This selects the processes whose executable name is
                given in cmdlist.

6
一个小缺点与OP的问题实际上没有关系,就是这种方法不能显示像Tomcat这样作为Java运行且带有一大堆参数的应用程序。 - Charles Wood
“-C” 选项在一年半之前的@Andreas Frishe的答案中已经提到了… - Piotr Dobrogost

5

免责声明:本工具的作者是我,但是...

我会使用 px

~ $ px atom
  PID COMMAND          USERNAME   CPU RAM COMMANDLINE
14321 crashpad_handler walles   0.01s  0% /Users/walles/Downloads/Atom.app/Contents/Frameworks/Electron Framework.framework/Resources/crashpad_handler --database=
16575 crashpad_handler walles   0.01s  0% /Users/walles/Downloads/Atom.app/Contents/Frameworks/Electron Framework.framework/Resources/crashpad_handler --database=
16573 Atom Helper      walles    0.5s  0% /Users/walles/Downloads/Atom.app/Contents/Frameworks/Atom Helper.app/Contents/MacOS/Atom Helper --type=gpu-process --cha
16569 Atom             walles   2.84s  1% /Users/walles/Downloads/Atom.app/Contents/MacOS/Atom --executed-from=/Users/walles/src/goworkspace/src/github.com/github
16591 Atom Helper      walles   7.96s  2% /Users/walles/Downloads/Atom.app/Contents/Frameworks/Atom Helper.app/Contents/MacOS/Atom Helper --type=renderer --no-san

除了可以找到具有合理命令行界面的进程外,它还可以做许多其他有用的事情,更多详细信息请参见项目页面

适用于Linux和OS X,易于安装:

curl -Ls https://github.com/walles/px/raw/python/install.sh | bash

1
这太棒了!! - Stefan Reich

3

在搜索模式中使用括号来包围字符可以排除 grep 过程,因为它不包含匹配的正则表达式。

$ ps ax | grep 'syslogd'
   16   ??  Ss     0:09.43 /usr/sbin/syslogd
18108 s001  S+     0:00.00 grep syslogd

$ ps ax | grep '[s]yslogd'
   16   ??  Ss     0:09.43 /usr/sbin/syslogd

$ ps ax | grep '[s]yslogd|grep'
   16   ??  Ss     0:09.43 /usr/sbin/syslogd
18144 s001  S+     0:00.00 grep [s]yslogd|grep

0

根据最终使用情况,通常更喜欢使用Awk。

ps aux | awk '/[t]erminal/'

当你有像这样的东西时,这尤其正确。

ps aux | grep '[t]erminal' | awk '{print $1}'  # useless use of grep!

很明显,正则表达式可以轻松地被分解成 Awk 脚本:

ps aux | awk '/[t]erminal/ { print $1 }'

但是真的,不要自己重新发明轮子。pgrep和它的伙伴们已经存在很长时间了,并且比大多数临时重新实现的解决方案更好地处理了整个问题空间。


-3
另一个选项是编辑您的.bash_profile(或其他保存bash别名的文件),创建一个函数来从结果中grep出“grep”。
function mygrep {
grep -v grep | grep --color=auto $1
}

alias grep='mygrep'

grep -v grep 必须放在最前面,否则你的 --color=auto 会因某种原因而无法起作用。

如果你使用的是 bash,则此方法有效; 如果您使用不同的 shell,则可能会有所不同。


1
别名和函数有什么关系?只需执行function grep { command grep -v grep | command grep --color=auto "$@"; }(还要注意参数和引用的修复)。然而,这样做会导致任何非“ps”调用“grep”的操作都无法正常工作(参数传递不正确)。总之,一个更有用的函数应该是修改正则表达式使其不匹配自身,而不是单独从“grep”结果中过滤出“grep”。当然,对于一个几十年前就已经解决了的问题,发明新的解决方案并不是很有效率。 - tripleee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接