【问题标题】:How to grep multiple terms and output in the order of the search?如何grep多个词并按搜索顺序输出?
【发布时间】:2013-09-07 17:05:26
【问题描述】:

我尝试了一些方法,但似乎没有取得任何进展 - 我有一个包含一些数据行的文本文件,我想要从该文件中获取一些数据行。每行都有一个唯一的标识符,我可以 grep。

如果我使用

grep 'name1\|name2\|name3\|name4' file.txt > newfile.txt

它完成了工作并 greps 我想要的所需行,但是,我想要按照我指定的顺序排列的行 - 在这个例子中,我首先想要 name1 行,然后是 name2 行,然后是 name3 行,最后是 name4线。

但是,例如在我的原始文件中,行的顺序是 name2,然后是 name4,然后是 name3,然后是 name1,输出文件似乎也有这个顺序的行。

有没有办法轻松订购 grep?

id 是按块排序的,因此所有带有 name1 的行都彼此相邻。

感谢您的建议!

【问题讨论】:

  • 恐怕grep不支持这个要求。您可能需要遍历单词并一次 grep 一个单词。

标签: macos unix command-line grep


【解决方案1】:

使用循环从文件中读取单词

给定一个单词文件,以 grep 查询如下:

root
lp
syslog
nobody

您可以使用读取循环重复 grep 以获取另一个文件中的固定字符串。例如,使用 Bash shell 的默认 REPLY 变量和存储在 /tmp 目录中的 word 文件,这将起作用:

while read; do
    grep --fixed-strings "$REPLY" /etc/passwd
done < /tmp/words

注意事项

  1. 发布的示例不会阻止多个匹配,但它将确保按照/tmp/words 中定义的顺序进行匹配。
  2. 出于性能原因,该示例使用 GNU grep 和固定字符串。您的里程可能会因其他 grep 和正则表达式而异。

【讨论】:

    【解决方案2】:

    您可以使用 awk 数组。

    awk 'BEGIN { k[1]="name1"; k[2]="name2"; k[3]="name3" }
    { for (i=1; i<4; ++i) if ($0 ~ k[i]) m[i]=(m[i]?m[i] RS:"") $0 }
    END { for(i=1; i<4; ++i) if (m[i]) print m[i] }' file
    

    如果一行匹配多个表达式,这将产生重复。如果您需要快速,可以对其进行一些优化;随便问问。

    或者在 Perl 中:

    perl -ne 'BEGIN { @k = qw( name1 name2 name3 name4 );
        $k = join("", "(", join("|", @k), ")");
        $r = qr($k); }
      if(m/$r/) { push @{$m{$1}}, $_ }
      END { for $i (@k) { if ($m{$i}) {
        print join("", @{$m{$i}}); } } }' file
    

    这可能比等效的 Awk 脚本更有效。每行只能找到一个匹配项,因此并不完全等价。

    【讨论】:

    • ...但从表面上看,Awk 显然更漂亮。在 Awk 中缺少嵌套数组有点令人遗憾,但是在 Perl 中使用 backref 作为数组键的能力是我编写第二个版本的真正原因。我想它也可以在 Awk 中完成,尽管不是很优雅。
    • 感谢您的建议!我真的希望有一些更简单的东西 - 我会调查这些建议!
    【解决方案3】:

    一个蹩脚的解决方案可能是......多次运行 grep 命令(也许你可以将它粘贴到 shell 脚本中并多次运行)

    grep 'name1' file.txt > newfile.txt
    grep 'name2' file.txt >> newfile.txt
    grep 'name3' file.txt >> newfile.txt
    grep 'name4' file.txt >> newfile.txt
    

    希望这会有所帮助!

    【讨论】:

    • 一个简单的改进方法是for word in "name1" "name2" "name3" "name4"; do grep "$word" file.txt; done &gt; newfile.txt。
    【解决方案4】:

    列表项

    我正在寻找相同的命令,但现在我想通了。

    第 1 步:为您的 grep 搜索创建文件。只需将 grep 单词粘贴到文件中,一行中粘贴一个 grep 关键字。例如,我制作文件 mySearch.txt。

    更多 mySearch.txt

    名称2
    名称3
    名称1
    名称4
    名称2
    姓名1

    第 2 步:现在使用此命令
    grep -Fwf mySearch.txt file.txt>newfile.txt
    或
    cat file.txt|grep -Fwf mySearch.txt >newfile.txt

    Thais 命令将首先打印所有带有 name2 的行,然后是 name3,依此类推,在 newfile.txt 的末尾打印 name1 行。

    【讨论】:

      【解决方案5】:

      perl 会更适合这种搜索和打印。

      perl -lne '/name1/?push @a,$_:
                (/name2/?push @b,$_:
                (/name3/?push @c,$_:
                 /name4/?push @d,$_:next));
                END{print join "\n",@a,@b,@c,@d}' your_file
      

      下面测试:

      > cat temp
      1 name1
      2 name2
      3 name3
      4 name1
      5 name4
      6 name2
      7 name1
      > perl -lne '/name1/?push @a,$_:(/name2/?push @b,$_:(/name3/?push @c,$_:/name4/?push @d,$_:next));END{print join "\n",@a,@b,@c,@d}' temp
      1 name1
      4 name1
      7 name1
      2 name2
      6 name2
      3 name3
      5 name4
      > 
      

      好问题 :)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-03-14
        • 2017-07-30
        • 1970-01-01
        • 1970-01-01
        • 2019-06-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多