如何按搜索顺序grep多个术语和输出?

时间:2013-09-04 09:06:29

标签: macos unix command-line grep

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

如果我使用

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

它可以完成工作并且可以获得我想要的所需行,但是,我希望按照我指定的顺序排列 - 从这个例子中我首先想要name1行,然后是name2行,然后是name3行,最后是name4线。

但是,例如在我的原始文件中,行的顺序是name2,后跟name4,后跟name3,后跟name1,输出文件似乎也按此顺序排列。

有没有办法轻松订购grep?

id是按块排序的,因此所有名称为1的行都会彼此相邻。

感谢您的任何建议!

5 个答案:

答案 0 :(得分:3)

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

给出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和固定字符串。您的里程可能因其他greps和正则表达而有所不同。

答案 1 :(得分:1)

您可以使用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脚本更有效。它每行只能找到一个匹配,所以它并不完全等价。

答案 2 :(得分:0)

一个蹩脚的解决方案可能是..多次运行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

希望这有帮助!

答案 3 :(得分:0)

列出项目

我看起来同样的命令,但现在我想出来了。

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

更多mySearch.txt

NAME2
NAME3
NAME1
NAME4
NAME2
NAME1

步骤2:现在使用此命令
grep -Fwf mySearch.txt file.txt&gt; newfile.txt

cat file.txt | grep -Fwf mySearch.txt&gt; newfile.txt

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

答案 4 :(得分:-1)

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

下面的Testde:

> 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
> 

虽然好问题:)