更优雅的“ps aux | grep -v grep”

Posted

技术标签:

【中文标题】更优雅的“ps aux | grep -v grep”【英文标题】:More elegant "ps aux | grep -v grep" 【发布时间】:2012-03-11 15:42:14 【问题描述】:

当我检查进程列表并“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 来删除最后一个条目...但它不是优雅 :)

你有没有更优雅的 hack 来解决这个问题(除了将所有命令包装到一个单独的脚本中,这也不错)

【问题讨论】:

不管怎样,这是一个古老的常见问题解答。请参阅faqs.org/faqs/unix-faq/faq/part3 上的第 3.10 项 感谢您的参考。这就是他们的方法:ps ux | awk '/name/ && !/awk/ print $2' grep -v grep 部分在做什么? @Jwan622 grep -v grep 从 grep 结果中排除 grep。如果 grep 与 ps 结合使用,那么也会显示 grep 进程(带有 grep 参数),从而使结果混乱。 grep -v grep 是避免这种情况的常用方法 【参考方案1】:

根据最终用例,您通常更喜欢 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 和朋友们已经存在很长时间了,并且比大多数临时重新实现更好地处理整个问题空间。

【讨论】:

【参考方案2】:

此答案基于之前的 pgrep answer。它还建立在另一个answer 的基础上,结合了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

【讨论】:

见github.com/blueyed/oh-my-zsh/blob/…(但它是Zsh特有的)。 @blueyed,我已经用 bash 函数定义更新了答案。 还要注意-d选项来指定分隔符;例如ps -fp$(pgrep -d , getty) 我用这个:ps uxp `pgrep <process>` 注意p 必须是最后一个参数(即pux 不起作用) 这不会像grep 那样为搜索进程名称着色【参考方案3】:

通常的技巧是这样的:

ps aux | egrep '[t]erminal'

这将匹配包含terminal 的行,而egrep '[t]erminal' 不匹配!它也适用于许多 Unix 风格。

【讨论】:

这适用于我的任意字符串,但不适用于用户名,例如ps aux | grep '[r]oot' 。有谁知道为什么? @kxsong: | grep '[t]erminal' 选择任何包含“终端”一词的行,而不将“终端”一词放入进程列表。你想用| grep '[r]oot' 达到什么目的,它怎么不起作用?可能会有更好的解决方案。 如果我错了,请纠正我,但这也适用于 grepped 字符的任何位置:ps aux| grep "te[r]minal" brilliant hack(我想我应该这么称呼它,因为 aux / grep 作者可能没有想到这种情况。) @JamieJag:嗯...就像我在帖子中所说,grep '[t]erminal' 将匹配包含terminal 的行。 ps aux 的输出将有一行 grep '[t]erminal'(带方括号),其中不包含字符串 terminal(没有相同)。【参考方案4】:

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

我会使用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

除了使用合理的命令行界面查找进程外,它还可以做很多其他有用的事情,更多详细信息请参见the project page。

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

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

【讨论】:

这太棒了!! 谢谢斯特凡 :)【参考方案5】:

另一个选项是编辑您的.bash_profile(或您保留 bash 别名的其他文件)以创建一个从结果中 grep 'grep' 的函数。

function mygrep 
grep -v grep | grep --color=auto $1


alias grep='mygrep'

grep -v grep 必须放在首位,否则您的 --color=auto 将因某种原因无法工作。

如果您使用的是 bash,则此方法有效;如果您使用的是不同的外壳 YMMV。

【讨论】:

别名的功能是什么?只需执行function grep command grep -v grep | command grep --color=auto "$@"; (还要注意参数和引用的修复)。但是,这被破坏了,因为任何非ps 调用grep 将不再起作用(参数传递不正确)。无论如何,一个更有用的功能是修改正则表达式以使其不匹配自身,而不是从grep 结果中单独过滤掉grep。当然,为几十年前已充分解决的问题发明新的解决方案并不是很有成效。【参考方案6】:

使用pgrep。它更可靠。

【讨论】:

pgrep 如果我寻找例如ps aux | grep 'ssh options' 将无法工作 Jakub M.:pgrep -f 呢? @jakub-m 默认情况下,pgrep 仅将模式与进程名称匹配。要匹配整个命令,请使用 -f 标志。 pgrep 只返回进程 ID。 旧版本采用pgrep -fl(但如果没有-f 匹配完整的cmdline,则无法看到完整的cmdline,详细信息:serverfault.com/a/619788/44183)。但是,如果您需要 pid、cmdline 之外的任何其他信息,则需要 ps。可以将它们组合起来:ps -p $(pgrep -f foo)【参考方案7】:

可以在ps命令中进行过滤,例如

ps u -C gnome-terminal

(或使用 find 等搜索 /proc)

【讨论】:

请注意,这适用于 GNU 的 ps (Linux),但不适用于 BSD ps。 即使使用 GNU ps 也是不正确的。 ps -C <command> 将匹配确切的命令。当与ax 选项一起使用时,它将报告所有进程,因为ax 列出进程除了通过其他方式匹配的进程集。 @Animism True。谢谢,我修好了。 这只有在进程名称被准确指定的情况下才有效。它不适用于部分匹配,例如logind 用于systemd-logind,或匹配参数。【参考方案8】:

使用方括号将搜索模式中的字符括起来会排除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

【讨论】:

【参考方案9】:

还有一个alternative:

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.

【讨论】:

一个小缺点,与 OP 的问题无关,它不会向您显示 Tomcat 之类的东西,它实际上是作为带有大量参数的 java 运行的。 -C 选项已在@Andreas Frishe 一年半前发布的答案中提出......

以上是关于更优雅的“ps aux | grep -v grep”的主要内容,如果未能解决你的问题,请参考以下文章

同时声明多个变量的更优雅的方式

toString 更优雅的实现方式

怎么让你的Python代码更优雅!

牛顿方法有更优雅的 Go 实现吗?

2022-06-16——在 Vue 中更优雅的封装第三方组件

让你的JS更优雅的小技巧