【问题标题】:Using grep to find lines that each contain ALL search strings使用 grep 查找每个包含所有搜索字符串的行
【发布时间】:2014-05-18 00:18:48
【问题描述】:

我有一个文件,其中包含很多与此类似的行:

{"id": 2796, "some_model": "Profile", "message_type": "MODEL_SAVE", "fields": {"account": 14, "address": null, "modification_timestamp": "2014-03-19T10:46:33.543Z", "was_deleted": false}}

然后我想找到所有包含我想要的相应行的一些片段的行。将在上面的示例行中应用的示例是:

~$ grep '2796' file.log | grep 'Profile' | grep 'another_more' | grep 'so_on'

我尝试以与上述相同的方式进行操作,EDITED:它确实有效,但不足以带来所有必要的数据。我的意思是,搜索结果中缺少数据。 :(

按照grep 'word' filename 的想法,它可以工作,但在大量数据中仅一个词是不够的。那么,如何传递多个“单词”来匹配我真正想要的?我真正想要的是同时使用 grep 通过 'ID'、'*some_model*' 和 'account' 进行搜索。

如何进行搜索以匹配提示中所有可能的行与这些参数? 这更像是一个疑问,是否可以使用 ifelse o while 之类的条件也可以与 grep 结合使用?

如果问题不清楚,请告诉我更正。 谢谢大家。

【问题讨论】:

  • 是的,你的问题不是很清楚。示例可能会有所帮助。
  • @devnull,好的。已编辑!谢谢! :D
  • 你想要匹配所有单词或任何单词的行吗?
  • @devnull,所有的话。
  • 听起来您想要以下内容:您想要查找每个包含在 ANY ORDER 中指定的所有搜索字符串的行。你能确认一下吗?顺便说一句,您的 grep ... | grep ... 方法应该有效,但效率低下 - 也许这就是您要问的原因:寻找更有效的解决方案。

标签: linux bash grep


【解决方案1】:

你可以使用sed:

sed '/string1/!d; /string2/!d; /string3/!d; /string4/!d' filename

这将只生成包含任何顺序的所有字符串的行。

同样的事情使用awk:

awk '/string1/ && /string2/ && /string3/ && /string4/' filename

【讨论】:

  • +1;巧妙利用sed;以 any 顺序匹配包含 all 字符串的行。
【解决方案2】:

这个问题专门询问grep,但实际上sedawk 对于'a AND b' 风格的匹配要干净得多,请参阅How to run grep with multiple AND patterns?

这个答案涵盖了如何使用 grep 来匹配匹配所有输入的所有行 - my other answer 涵盖匹配任何输入。

注意grep 比简单的单词匹配更强大,它可以匹配任意模式,包括多个单词。

考虑您提供的示例的以下简化版本:

$ cat file
{"id": 2796, "some_model": "Profile", "was_deleted": false}
{"id": 2797, "some_model": "Profile", "was_deleted": true}
{"id": 2798, "some_model": "Another", "was_deleted": false}

您可以像这样找到项目 2796:

$ grep '"\?id"\? *: *2796 *,\?' file
{"id": 2796, "some_model": "Profile", "was_deleted": false}

或者查找所有未删除的项目:

$ grep '"\?was_deleted"\? *: *false *[,}]' file
{"id": 2796, "some_model": "Profile", "was_deleted": false}
{"id": 2798, "some_model": "Another", "was_deleted": false}

您甚至可以将两者结合起来,仅在未删除项目 2796 的情况下获取它(将 false 更改为 true 并且该行不再匹配):

$ grep '"\?id"\? *: *2796 *,\?.*"\?was_deleted"\? *: *false *[,}]' file
{"id": 2796, "some_model": "Profile", "was_deleted": false}

或大致等价,使用您在上面使用的 grep 管道语法:

$ grep '"\?id"\? *: *2796 *,\?' file | grep '"\?was_deleted"\? *: *false *[,}]'
{"id": 2796, "some_model": "Profile", "was_deleted": false}

希望这些示例看起来很难正确,因为这不是一个好主意!

您正在处理的数据看起来是 JSON,这是一种结构化数据格式,grep 不太适合处理。有效的 JSON 可以拆分为多行或具有任意顺序的字段,这将破坏上述模式。更不用说上述模式应该处理的任意空格 (*)、半可选引号 ("\?) 和字段结束与对象结束标记 ([,}]),但很容易获得错了。

如果您尝试查询 JSON 数据,则需要 JSON 解析器,而 grep 则不需要。 http://www.json.org/ 提供了多种语言的几种流行 JSON 解析器的链接,看看是否有适合您的需求。使用真正的工具比尝试构建复杂的正则表达式获得更好的成功。

【讨论】:

【解决方案3】:

awk 版本。这对查找顺序有限制,因此string1 位于string2 之前

awk '/string1.*string2.*string3.*string4/' filename

【讨论】:

    【解决方案4】:

    我相信官方 GNU grep 文档中已经回答了这个问题:

    http://www.gnu.org/savannah-checkouts/gnu/grep/manual/grep.html#Usage

    10.  I can do “OR” with ‘|’, but what about “AND”?
    
        grep 'paul' /etc/motd | grep 'franc,ois' 
    
    finds all lines that contain both ‘paul’ and ‘franc,ois’.
    

    看起来是使用grep 实现逻辑AND 的唯一方法,它不依赖于找到匹配模式的顺序。

    【讨论】:

      【解决方案5】:

      这个答案涵盖了如何使用 grep 来匹配与多个输入之一匹配的所有行 - my other answer 涵盖匹配所有输入,这是 OP 实际上正在寻找的。我怀疑这个答案通常是人们正在寻找的,所以我把它留在这里。

      -e 参数可让您搜索多个不同的匹配项:

      $ cat file
      Hello World
      Nope
      Foo Bar
      
      $ grep -e Hello -e Foo file
      Hello World
      Foo Bar
      

      您还可以使用| 字符在单个查询中分隔多个匹配项,但您必须使用\ 对其进行转义并引用查询字符串,如下所示:

      $ grep 'Hello\|Foo' file
      Hello World
      Foo Bar
      

      或者使用 f 标志在文件中指定 grep 使用模式:

      $ cat patterns
      Hello
      Foo
      
      $ grep -f patterns file
      Hello World
      Foo Bar
      

      不用说,我个人更喜欢使用-e,但是有很多选择。

      【讨论】:

      • 它是否匹配任何带有“第一个或第二个单词”的行或仅匹配“同一行的第一个和第二个单词”?
      • @osgx,好问题!
      • 我的示例返回匹配任何提供的模式的行。问题中发布的grep A | grep B | grep C 模式将让您找到在同一行中包含ABC 的行。
      猜你喜欢
      • 2012-05-07
      • 2013-05-13
      • 1970-01-01
      • 2020-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-03-20
      • 1970-01-01
      相关资源
      最近更新 更多