如何防止'grep'出现在ps结果中?


304

当我搜索一些不存在的过程时,例如

$ ps aux | grep fnord                          
wayne    15745  0.0  0.0  13580   928 pts/6    S+   03:58   0:00 grep fnord

显然,我不在乎grep-与搜索ps过程一样有意义!

如何防止grep出现在结果中?


28
如果仅需要进程的PID,则可以替换ps aux |greppgrep(或pgrep -f)。
jofel 2013年

6
对同一个问题Serverfault超级用户
2013年

这是合法的输出吗?似乎没有名为fnord的程序正在运行...
acolyte

4
@acolyte,就是这样-但是因为它将输出管道输送到grep中,所以grep正在运行(等待的输出ps aux,我希望是这样)。所以,问题是如何防止grep fnord从显示为正在运行的进程,因为很明显,我不感兴趣的一个。
韦恩·沃纳

2
@acolyte,您看不到“ fnord”行并不奇怪。您不应该能够看到它。如果您有2到3分钟的空闲时间,请进行搜索。
弗朗切斯科

Answers:


439

事实证明,在钥匙串中找到了一个解决方案。

$ ps aux | grep "[f]nord"

通过将括号括在字母和引号周围的字符串中,您可以搜索正则表达式,即“找到字符'f'后跟'nord'”。

但是由于您将方括号放在模式“ f”中,然后是“]”,因此grep不会出现在结果列表中。Neato!


26
@acolyte:ps的输出将包含以结尾的行grep [f]nord。但是,该行不会通过grep过滤器加入,因为该字符串[f]nord与正则表达式不匹配[f]nord
LarsH 2013年

9
@LarsH有趣,谢谢!我本来会建议的ps aux | grep fnord | grep -v grep……似乎已经有人建议了……大声笑
acolyte 13-4-30

5
@progo是的,您确实需要[在bash中引用even。尝试使用fnord当前目录中名为的文件。
吉尔斯

25
掌握的输出ps可能是一个古老的技巧,但这并不可靠。如果可用,pgrep使用。
吉尔斯

8
@naxa假设您有一个程序调用fnord和一个名为的程序safnorde。或有一个名为的用户bfnord,您最终将杀死他的所有进程。等等
Gilles

163

我使用的另一个选项(特别是仅用于查看进程是否正在运行)是pgrep 命令。这将搜索匹配的过程,但不会列出搜索的grep行。我喜欢它,因为它是一种快速搜索的方法,无需重新定义或转义任何内容。

pgrep fnord

8
他们将希望该-f选项更像ps | grep
jordanm 2013年

@jordanm实际上,pgrep -f它将看起来更像ps -f | grep
michelpm 2013年

5
还有一个-l参数可以使它显示要匹配的命令。
帕特里克

15
ps | grep '[f]nord'是聪明而古老的,但是pgrep是正确的
kojiro

3
ps $(pgrep cmd) ...如果pgrep缺少选项,您总是可以做的(尽管它不适用于空命令集)。
Maciej Piechotka

62

理想的解决方案是BriGuy提出的解决方案

pgrep fnord 

但是,如果您不想这样做,则可以使用以下命令排除所有与grep匹配的行:

ps aux | grep -v grep | grep "fnord"

7
但是,如果我要查找的行是“ bash bash grep bash”,该怎么办?
Sparr

1
@Sparr然后,您应该使用最佳解决方案:pgrep或者找到另一个解决方案;)
RSFalcon7 2013年

注意使用pgrep的名称长度限制。使用-f获取完整的路径名,否则您可能会发现匹配失败而使用了更长的名称。-l也不错列出的比赛
尼尔·麦吉尔

25

不是最优雅的解决方案,但是您可以这样做:

$ ps aux | grep fnord | grep -v grep


这是一个不好的答案!因为如果grep您的短语中有一个单词。它不会显示该过程。例如,假设命令foo_grep_bar.txt正在编辑一个名为的文件nano。因此,有一个进程正在运行:root 14908 0.0 0.0 110012 1692 pts / 3 S + Oct31 0:00 nano foo_grep_bar.txt根据此答案,这将不起作用:$ ps aux | grep nano | grep -v grep因为文件名中包含grep单词。
纳比·卡兹

我更喜欢此方法,因为它比预期的答案更明确地表示其意图,并且除了一种情况外,其他方法均适用。
samaspin

1
按照superuser.com/a/409658/450260你应该不包括完整的grep fnord不仅仅是grep$ ps aux | grep fnord | grep -v "grep fnord"
达沃斯

15

在zsh中grep fnord =(ps aux)

这个想法是,首先运行ps aux,将结果放入文件中,然后grep在该文件上使用。只是,我们没有文件,因为我们使用zsh的“进程替换”。

为了说明,尝试

ps aux > ps.txt
grep fnord ps.txt
rm ps.txt

结果应该是相同的。

对其他一些答案的一般评论。有些非常复杂和/或冗长。这不仅是正确的问题,它也应该可用。但这并不意味着其中一些解决方案是不好的;仅,它们必须包装在微型UI中才能使用。


1
不知道zsh的进程替换,但是可以确定两个进程被称为一个接一个而不是并行吗?
圣保罗Ebermann

3
@PaŭloEbermann:因为平行<(command)grep grep =(ps aux)不显示任何行。
Maciej Piechotka

Zsh还可以“匹配” ps的输出。print -l ${(M)${(f)¨$(ps aux)¨}:#*fnord*}
Friartek

7
ps aux | grep $(echo fnord | sed "s/^\(.\)/[\1]/g")

3
这看起来像一个IOCCC,但是对于unix命令行而不是C ^^ | grep $(echo fnord)还不够吗?您还要求sed搜索并用其自身的值替换“ nord”中的每个字符?^^恭喜。我敢打赌,我可以做更长的时间,但可能不会那么有趣^^
Olivier Dulac 2013年

1
抱歉,我的上述言论听起来令人反感(5百万之后我无法编辑)...您的回答确实是令人愉快的阅读,而我并不是想让您看起来很糟。我真的认为您是故意这样做的^^
Olivier Dulac

1
抱歉,您的答案阅读起来确实很有趣(也很特别)。我的意思是pgrep -l $ 1;)
yPhil

3
@OlivierDulac:他不只是将第一个字符替换为其自己的值;他将其值替换为方括号中的值。(那些方括号并不特殊,它们是文字。)基本上,他是对Wayne Werner的回答的概括,因此可以编写将第一个字符放在方括号周围的过程的脚本。+1
LarsH 2013年

2
ps aux | grep '[^]]fnord'会避免这种体操。
斯特凡Chazelas

6

answer 此答案是特定于GNU的。有关更一般的解决方案,请参见韦恩的答案

搜索流程

如果您只是在寻找fnord进程,则可以使用该-C选项按命令名称进行选择:

ps -C fnord

可以将BSD和POSIX样式的格式选项混合使用。有关完整列表,请参见ps手册页

寻找其他东西吗?

如果您需要比精确搜索命令名称更高级的功能,请不要放过希望!这仍然可以ps在管道的侧面完成。我们要做的就是告诉从结果中ps排除grep流程:

ps -NC grep | grep 'fnord'

-C grep选择所有grep进程,并-N否定选择。这可用于搜索命令参数,命令名称的一部分或更复杂的正则表达式。


1
这对GNU来说很好,ps但是-CPOSIX未指定,在BSD上有完全不同的含义
Eric Renouf

没有BSD等效项真是令人really目结舌(这也意味着它不能在Mac上运行)。到目前为止,使用ps -C是所有方法中最简单的答案。
Christopher Hunter,

3

我的答案是在“ ps”列表中搜索“ foobar”的典型答案的变体。我相信,“-A”“ ps”的论点比“ aux”更可移植,但是这种变化与答案无关。典型的答案如下所示:

$ ps -A -ww | grep [f]oobar

相反,我使用这种模式:

$ ps -A -ww | grep [^]]foobar

主要优点在于,基于这种模式编写脚本更加容易,因为您只需将静态字符串“ [^]]”与所需的任何模式连接即可。您无需剥离字符串的第一个字母,然后将其插入方括号之间,然后再次将其连接在一起。使用shell脚本编写脚本时,只需将“ [^]]”粘贴到您正在寻找的模式前面就容易了。Bash中的字符串切片是一个丑陋的事情,因此我的修改避免了这种情况。此变化表示在不匹配前导右方括号]的情况下显示模式匹配的线。由于排除方括号的搜索模式实际上会将方括号添加到模式中,因此它永远不会匹配自己。

因此,您可以编写一个可移植的“ psgrep”命令,如下所示。在这里,我考虑了Linux,OS X BSD和其他操作系统之间的差异。这会添加“ ps”中的列标题,提供一种更适合我的需要的自定义“ ps”格式,并显示列出额外,更宽范围的进程,从而不会遗漏任何命令行参数。好吧,大多数都不会错过。Java是Java,它通常以最坏的方式进行操作,因此您某些Java服务将超出进程表将跟踪的参数的最大允许长度。我相信这是1024个字符。允许启动进程的命令单独长度要长得多,但是内核进程表不会费心跟踪任何长度超过1K的内容。启动命令后,命令名称和参数列表为“

psgrep ()
{
    pattern=[^]]${1};
    case "$(uname -s)" in
        Darwin)
            ps -A -ww -o pid,ppid,nice,pri,pcpu,pmem,etime,user,wchan,stat,command | grep -i -e "^[[:space:]]*PID" -e ${pattern}
        ;;
        Linux)
            ps -A -ww -o pid,ppid,tid,nice,pri,pcpu,pmem,etime,user,wchan:20,stat,command | grep -i -e "^[[:space:]]*PID" -e ${pattern}
        ;;
        *)  # other UNIX flavors get a minimalist version.
            ps -A -ww | grep -i -e ${pattern}
        ;;
    esac
}

2

与外壳无关的最简单方法是首先将其存储在变量中:

PS_OUTPUT="$(ps aux)"; echo "$PS_OUTPUT" |grep fnord

标注:@EmanuelBerg的grep fnord =(ps aux)答案到目前为止是最优雅的,尽管它要求zsh。我曾在rc文件中短暂地使用过它,但是bash抱怨该语法,即使有条件应阻止其评估。


从我的rc文件中,我有一个不区分大小写的版本,它使用grep的args:

psl() {
  local PS_OUTPUT="$(ps auxww)"
  echo "${PS_OUTPUT%%$'\n'*}" >&2  # title, in stderr to avoid pipes
  echo "${PS_OUTPUT#*$'\n'}" |grep -i "${@:-^}"
}

代码遍历,每行代码一个项目符号:

  • 捕获详细ps输出(在local变量中,以便在函数返回时消失)
  • 以标准错误显示第一行(标题),以便可以进一步过滤结果而不会影响标题。替换内容表示:$PS_OUTPUT在第一个换行符之后取出并删除所有内容(正则表达式等于:)s/\n.*$//msg。这可以防止我们重复标题
  • 显示除了第一行(regex equiv:)以外ps所有内容的输出,并用不区分大小写的grep内容和不带参数的所有参数传递给该函数(如果没有参数,则匹配要匹配的任何行的开头)一切)s/^.*\n//m-i^

1

也许这次是时候使用真实的序列了。使用管道使其平行。

ps aux >f && grep tmpfs <f

麻烦的是,因为会有一个文件f,但是对于顺序流程没有语法,这仍然不是我的错,在顺序语法中您仍然想使用以前运行的流程的输出。

有关顺序运算符的语法的建议:

ps aux ||| grep tmpfs

普通人无法轻松过滤流,这几乎不是精英阶层以序列为基础的原因。这将是计算方面的倒退。
Acumenus 2014年

@ABB en.wikipedia.org/wiki/Communicating_sequential_processes的运算符比Thompson shell中的运算符还要多。可能只是一个顺序操作符,该操作符在退出后立即将其结果传递给顺序中的下一个进程。通过提供额外的运算符来“向后退一步”似乎有些苛刻。
安妮·范·罗苏姆

链接很好,但是相对于并行处理,顺序处理在CPU和内存(或磁盘)使用方面都更差。在这种情况下,如果我必须先存储所有ps输出,然后再grep使用更多的内存(或磁盘),则时间会更长。
Acumenus

0

正如其他人所说,pgrep命令将根据名称和其他属性返回进程的PID(进程ID)。例如,

pgrep -d, -u <username> <string>

会为您提供PID,以名称(由user运行)匹配的所有进程的逗号(,)分隔<username>。您可以在使用-x开关之前仅返回完全匹配项。

如果要获取有关这些进程的更多信息(如从ps运行aux选项所暗示的),则可以将-p选项与ps一起使用,该选项根据PID进行匹配。因此,例如

ps up $(pgrep -d, -u <username> <string>)

将给出pgrep命令匹配的所有PID的详细信息。


ps如果pgrep返回空集,则失败。我有一个基于您的答案,并试图解决此问题。
Acumenus 2014年

0

这是一个简单的示例,用于查找ssh-agent用户名的PID而不显示grep进程本身的PID :

ps xu | grep "${USER}.*[ ]/usr/bin/ssh-agent" | awk '{print $1 $2;}'

例如,如果要杀死ssh-agent当前用户,则可以使用以下命令:

kill `ps xu | grep "${USER}.*[ ]/usr/bin/ssh-agent" | awk '{print $2;}'`

要创建一个方便的别名,请将以下代码添加到〜/ .bashrc或〜/ .zshrc文件中:

function function1 () {
    ps xu | grep "$1.*$2" | awk '{print $1" "$2" "$11;}'
}
alias mygrep="function1"

并使用别名来强制所有人学习正则表达式的示例:

. /etc/profile #to make alias usable
mygrep ${USER} ${PROCESS_PATH}
mygrep ${USER} "[f]nord"
mygrep "[f]nord"
mygrep ".*[s]shd"

PS我只在Ubuntu和Gentoo上测试了这些命令。


(1)问题并不是说用户正在寻找自己的过程之一,而是用户可能不知道他正在寻找的过程的所有者。(2)就像这个答案一样,如果您说了,它仍然会失败"${USER}.* /usr/bin/ssh-agent"。之所以有效是因为你说过[ ]; 即,您只是在使用接受答案的机制。您可能还只是grep "[s]sh-agent"
G-Man

你是对的。(1)我分享了一些有用的信息,因为我发现自己偶尔遇到此页面(2)是的,我像接受的答案一样使用了正则表达式。(3)我将答案更新为与接受的答案相同,因为更好,但是我也展示了如何在提供或不提供用户名的情况下使用别名。(4)还显示了如何定义函数,虽然不是必需的,但是它以有趣的方式工作,因为$ 1和$ 2不重叠。Thx#G-Man
Constantin Zagorsky 2015年

-1

您可以轻松地做到这一点,只需.bashrc 像这样定义ALIAS :

alias grep='grep -v grep | grep'

不知道是谁拒绝投票或为什么投票,但是这可以让您充分利用pgrep不能使用的ps。
opticyclic

这不仅无意中排除了其他grep进程;grep在其他情况下也会中断使用。尝试echo I love grep | grep love
trosos

@trosos近11年以来,我一直在* nixing ..且从未使用过这种模式...也许明年吧-谁知道呢。
a20

-1

使用-x(完全匹配)选项对我有用。我将它与-f(完整的命令行)结合使用,因此我的过程可以精确地与:

pgrep -x -f "path_i_used_when_starting/cmd params_i_used"

谁在进行过分否决的人会自我解释?多年来,我一直在努力为我解决这个问题。
moodboom
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.