【问题标题】:How to grep for two words existing on the same line? [duplicate]如何grep存在于同一行的两个单词? [复制]
【发布时间】:2011-09-22 18:25:12
【问题描述】:

如何对包含两个输入单词的行进行 grep?我正在寻找包含这两个单词的行,我该怎么做?我试过这样的管道:

grep -c "word1" | grep -r "word2" logs

它只是在第一个管道命令之后卡住了。

为什么?

【问题讨论】:

标签: grep


【解决方案1】:

为什么要传递-c?那只会显示匹配的数量。同样,没有理由使用-r。我建议你阅读man grep

要查找同一行中存在的 2 个单词,只需执行以下操作:

grep "word1" FILE | grep "word2"

grep "word1" FILE 将从 FILE 中打印所有包含 word1 的行,然后grep "word2" 将打印其中包含 word2 的行。因此,如果您使用管道将它们组合在一起,它将显示同时包含 word1 和 word2 的行。

如果您只想计算在同一行中包含 2 个单词的行数,请执行以下操作:

grep "word1" FILE | grep -c "word2"

另外,为了解决您的问题,它为什么会卡住:在grep -c "word1" 中,您没有指定文件。因此,grep 期望来自stdin 的输入,这就是它似乎挂起的原因。您可以按 Ctrl+D 发送 EOF(文件结尾),使其退出。

【讨论】:

  • 当您感到困惑时,手册页几乎是您想要澄清的最后一个地方。它们比随机猜测更令人困惑。
  • @TotalFrickinRockstarFromMars:我不同意。确实,一开始它们可能看起来令人困惑,但是一旦您习惯了使用它们的格式,就会非常简单。无论如何,我将它更多地包含在“教人如何钓鱼”的答案中,我希望 OP 不知道它们,并且手册页可以非常方便。
  • @houbysoft 那么我们必须同意不同意。 8 年来我一直在使用 Linux 和朋友,但我仍然宁愿 google 也不愿使用手册页。
  • @TotalFrickinRockstarFromMars:嗯,我并不否认使用它。无论如何,您能否指出一些您在 grep 手册页中发现“令人困惑”的具体内容?
  • @geneorama 当然,但也许一开始就编写实用程序的人会编写更好的手册页,这不会成为问题。手册页是为已经了解该工具并且只需要一点提醒的人编写的。它们不是为试图弄清楚自己在做什么的人而写的。
【解决方案2】:

处方

问题中命令的一个简单重写是:

grep "word1" logs | grep "word2"

第一个 grep 从文件 'logs' 中找到带有 'word1' 的行,然后将这些行输入到第二个 grep 中,后者查找包含 'word2' 的行。

但是,没有必要使用两个这样的命令。您可以使用扩展的grepgrep -Eegrep):

grep -E 'word1.*word2|word2.*word1' logs

如果您知道 'word1' 将在 'word2' 之前出现,您甚至不需要替代品,而常规 grep 就可以了:

grep 'word1.*word2' logs

“一个命令”变体的优点是只有一个进程在运行,因此包含“word1”的行不必通过管道传递给第二个进程。这有多重要取决于数据文件的大小以及与“word1”匹配的行数。如果文件很小,则性能不太可能成为问题,运行两个命令就可以了。如果文件很大但只有几行包含“word1”,则管道上传递的数据不会太多,使用两个命令就可以了。但是,如果文件很大并且经常出现“word1”,那么您可能会将重要数据传递到管道中,而单个命令可以避免这种开销。与此相反,正则表达式更复杂。您可能需要对其进行基准测试以找出最好的——但前提是性能真的很重要。如果你运行两个命令,你应该选择第一个grep中出现频率较低的单词,以尽量减少第二个命令处理的数据量。

诊断

初始脚本是:

grep -c "word1" | grep -r "word2" logs

这是一个奇怪的命令序列。第一个grep 将计算“word1”在其标准输入上出现的次数,并在其标准输出上打印该数字。在您指示 EOF 之前(例如,通过键入 Control-D),它会坐在那里,等待您输入内容。第二个grep 在目录logs 下的文件中递归搜索“word2”(或者,如果它是一个文件,则在文件logs 中)。或者,就我而言,它会失败,因为我运行管道的地方既没有文件也没有名为logs 的目录。请注意,第二个grep 根本不读取其标准输入,因此管道是多余的。

使用 Bash,父 shell 会一直等待,直到管道中的所有进程都退出,因此它会一直等待 grep -c 完成,直到您指示 EOF 才会这样做。因此,您的代码似乎卡住了。使用Heirloom Shell,第二个grep 完成并退出,shell 再次提示。现在您有两个进程正在运行,第一个 grep 和 shell,它们都试图从键盘读取,并且不确定哪个进程获得任何给定的输入行(或任何给定的 EOF 指示)。

请注意,即使您在第一个 grep 中输入数据作为输入,您也只会在输出中看到包含“word2”的任何行。


脚注:

曾经使用的答案:

grep -E 'word1.*word2|word2.*word1' "$@"
grep 'word1.*word2' "$@"

这触发了下面的 cmets。

【讨论】:

  • “$@”有什么用,你能解释一下吗?你没有提到任何文件名。
  • @PrabhatKumarSingh:在 shell 脚本中,"$@" 扩展为传递给 shell 脚本的所有参数(没有被移走)。它可以是文件名列表,也可以为空,在这种情况下,grep 将从标准输入中读取。问题中的原始代码也没有提及任何文件名。因此,它将从标准输入中读取。
  • 好的,我理解 $@ 在 shell 脚本中的含义,但我没有看到您的回答中提到的 script,这就是为什么会感到困惑。
  • 加 1 以获得更有效的 grep grep 方式。
  • 这个解决方案的另一个好处是,如果两个单词相同,它就可以工作,这意味着它还可以检测一个单词是否在一行中重复。接受的解决方案不处理这种情况。 +1。
【解决方案3】:

你可以使用 awk。像这样……

cat <yourFile> | awk '/word1/ && /word2/'

顺序并不重要。因此,如果您有一个文件并且...

一个名为 的文件,file1 包含:

word1 is in this file as well as word2
word2 is in this file as well as word1
word4 is in this file as well as word1
word5 is in this file as well as word2

那么,

/tmp$ cat file1| awk '/word1/ && /word2/'

将导致,

word1 is in this file as well as word2
word2 is in this file as well as word1

是的,awk 更慢。

【讨论】:

  • 无用的cat(1)
  • 单个 awk 仍然可能比两个单独的 grep 进程快。 (当然,额外的useless cat 进程或多或少会抵消这种差异。)
【解决方案4】:

主要问题是您没有为第一个 grep 提供任何输入。您将需要重新排序命令,例如

grep "word1" logs | grep "word2"

如果您想计算出现次数,请在第二个 grep 上添加“-c”。

【讨论】:

    【解决方案5】:

    你试试下面的命令

    cat log|grep -e word1 -e word2
    

    【讨论】:

    • 这些命令搜索至少一个词,而不是全部。和猫|是不必要的,您可以将文件作为 grep 最后一个参数提供
    • 猫可能没用?!
    【解决方案6】:

    git grep

    这是使用git grep 使用布尔表达式组合多个模式的语法:

    git grep -e pattern1 --and -e pattern2 --and -e pattern3
    

    上面的命令会一次性打印匹配所有模式的行。

    如果文件不受版本控制,请添加 --no-index 参数。

    在当前目录中搜索非 Git 管理的文件。

    查看man git-grep 寻求帮助。

    另见:

    【讨论】:

      【解决方案7】:

      使用 grep:

      grep -wE "string1|String2|...." file_name
      

      或者你可以使用:

      echo string | grep -wE "string1|String2|...."
      

      【讨论】:

      • 这些命令搜索至少一个词,而不是全部
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-12-22
      • 1970-01-01
      • 2021-05-24
      • 2016-10-08
      • 2011-05-31
      • 1970-01-01
      相关资源
      最近更新 更多