【问题标题】:grep -f file to print in order as a filegrep -f file 按顺序打印为文件
【发布时间】:2014-03-21 10:55:34
【问题描述】:

我需要从文件中 grep 模式,但需要它们。

$ cat patt.grep
name1
name2

$ grep -f patt.grep myfile.log
name2:some xxxxxxxxxx
name1:some xxxxxxxxxx

我得到的输出是首先找到 name2 它被打印然后找到 name1 它也被打印。但我的要求是按照 patt.grep 文件的顺序先获取 name1。

我期望输出为

name1:some xxxxxxxxxx
name2:some xxxxxxxxxx

【问题讨论】:

  • @devnull 可能 patt.grep 中的模式未排序,OP 希望它们按 patt.grep 中的顺序排序。不幸的是,该示例可能具有误导性。
  • @mockinterface 但它的排序似乎就像看到$ cat patt.grep的输出一样
  • @JKB 我敢打赌它是未排序的。可以说这是经过多年阅读需求编写者的想法后产生的预感。会去睡觉,早上发现:)
  • @Sriharsha Kalluru 试试$ grep -f patt.grep myfile.log | sort -u
  • 这个命令的输出是myfile.log中出现的行的顺序,而不是patt.grep中的模式的顺序。 name2name1 之前出现在 myfile.log 中。 grep 一次遍历要搜索的文件一行,并将每一行与所有模式进行比较。如果您希望按模式顺序运行,则必须重复运行 grep,每个模式一次。

标签: linux bash shell grep


【解决方案1】:

您可以通过管道将patt.grep 传递给xargs,这会将模式一次传递给grep

默认情况下xargs 在命令末尾附加参数。但在这种情况下,grep 需要 myfile.log 作为最后一个参数。所以使用-I{} 选项告诉xargs 用参数替换{}

cat patt.grep | xargs -Ihello grep hello myfile.log

【讨论】:

  • 如果为patt.grep 中的每一行调用grep 在性能方面是可以容忍的,这是一个简单而实用的解决方案。 (不过,我建议使用 {} 或类似抽象的占位符,以避免混淆。)
【解决方案2】:

通过逐行阅读,依次使用patt.grep 中的正则表达式:

while read ptn; do grep $ptn myfile.log; done < patt.grep

【讨论】:

  • 如果有 n 个模式,而循环创建 n 个进程,我不喜欢那个。如果 grep 直接可用,我正在寻找一个通用选项。
  • 也许对grep -f patt.grep myfile.log的输出应用逐行匹配,然后呢?
  • 我不知道行匹配,请您提供命令。
【解决方案3】:

我尝试了同样的情况并使用以下命令轻松解决:

我认为如果您的数据与您所代表的格式相同,那么您可以使用它。

grep -f patt.grep myfile.log | sort

【讨论】:

  • 但我认为 OP 想要按照 patt.grep 文件列表进行排序。
  • 我提到name1和name2只是为了测试,但我的实际需求可能会用不同的词。
  • 然后你可以使用 "while read line; do grep $line myfile.log; done
【解决方案4】:

一个简单的解决方法是sortgrep之前的日志文件:

grep -f patt.grep <(sort -t: myfile.log)

但是,如果 patt.grep 未排序,这可能不会产生所需顺序的结果。

为了保留模式文件中指定的顺序,您可以改用awk

awk -F: 'NR==FNR{a[$0];next}$1 in a' patt.grep myfile.log

【讨论】:

  • 但我认为 OP 想要按照patt.grep 文件的列表进行排序。
  • @JKB 是的,awk 解决方案确实保留了模式文件中的顺序。
  • 实际上,awk 解决方案保留了 log(输入)文件中的顺序,而不是模式文件;它实际上与 OP 的原始命令相同,grep -f patt.grep myfile.log
【解决方案5】:

应该这样做

awk -F":" 'NR==FNR{a[$1]=$0;next}{ if ($1 in a) {print a[$0]} else {print $1, $1} }' myfile.log patt.grep > z

【讨论】:

  • 虽然这个 sn-p 可能会回答这个问题,但我们通常更喜欢对某事如何或为何如此的额外解释。你能解释一下吗?
  • 嗨,抱歉,所以:首先,myfile.log 使用 -F":" 拆分为列。然后我将内容加载到 a[$1]=$0 中。然后我说如果 patt.grep 的第一列(也是唯一的)列中列出的单词出现在 a 的第一列中(本质上是通过使用 -F":" 拆分创建的,并且按此顺序包含 name2、name1) ,然后我说打印整行,否则打印丢失的单词两次。所以如果在patt.grep中加入name3,输出为:name1:some xxxxxxxxxx name2:some xxxxxxxxxx name3 name3
【解决方案6】:

这不能单独在grep 中完成。

有关简单实用但效率低下的解决方案,请参阅owlman's answer。它在patt.grep 中为每个模式调用一次grep

如果这不是一个选项,请考虑以下方法:

grep -f patt.grep myfile.log |
 awk -F: 'NR==FNR { l[$1]=$0; next } $1 in l {print l[$1]}' - patt.grep
  • 一次性将所有模式传递给grep
  • 然后使用awk根据patt.grep中的模式顺序对它们进行排序:
    • 首先将所有输出行(通过标准输入,-,即通过管道)读入关联。使用第一个基于 : 的字段作为键的数组
    • 然后循环遍历patt.grep 的行并打印相应的输出行(如果有)。

约束

  • 假设patt.grep 中的所有模式都与日志文件中第一个基于: 的标记相匹配,正如问题中的示例输出数据所暗示的那样。
  • 假设每个模式只匹配一次 - 如果可能有多个匹配,awk 解决方案必须更加复杂。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-31
    • 1970-01-01
    • 2019-05-18
    • 1970-01-01
    • 1970-01-01
    • 2012-05-24
    • 1970-01-01
    • 2013-05-20
    相关资源
    最近更新 更多