Grep 大文件中不同元素的最后一次出现

问题描述 投票:0回答:1

我有一个文件,其中不同的元素在多行上重复。 我的文件包含这样的行:

1  $element_(1)
10 $element_(2)
20 $element_(1)
30 $element_(3)
40 $element_(1)
50 $element_(2)
60 $element_(3)
70 $element_(1)

我想获取每个元素的最后一次出现并将它们放入文件中

resultfile

50 $element_(2)
60 $element_(3)
70 $element_(1)

我试过了

for  i in {1..8000} do 
     grep $element_\($i\) sourcefile | tail -1 >> resultfile 
done

但它给了我错误。此外,如何区分作为字符串名称一部分的

$
和用于增加我正在搜索的元素数量的
$

另外,我也不知道文件中将包含多少个元素,因此我将 8000 作为最大值,但它可以更少或更多。

for-loop grep
1个回答
0
投票

按元素索引排序的输出

您可以告诉 grep 在找到第一个匹配项 (

-m 1
) 后停止,并且要使该匹配项成为文件中的最后一个匹配项,您可以将文件反向传输到 grep:

for i in {1..8000}; do
    tac sourcefile | grep -m 1 "\$element_($i)"
done > resultfile

我还将输出重定向移到循环之外,并修复了模式中的引用:我引用整个模式;第一个

$
必须被转义,这样 shell 就不会尝试扩展变量
$element_
,并且括号不能被转义,否则 grep 会认为它是一个捕获组。在您的尝试中,您正确地转义了它们,但这里通过引用整个模式来避免这种情况。

单引号模式通常更容易,因此我们不必关心 shell 扩展,但在这种情况下,我们希望

$i
真正扩展。

您的尝试存在语法错误,因为大括号后缺少

;

输出按输入文件中的出现顺序排序

如果行的顺序必须与输入文件中的顺序相同,我们可以在前面添加行号 (

nl
) 并在最后按行号排序 (
sort -n
),然后再次使用
cut
删除它们:

for i in {1..8000}; do
    nl sourcefile | tac | grep -m 1 "\$element_($i)"
done | sort -n | cut -f 2 > resultfile

第一次搜索失败后停止

如果我们知道元素索引是连续的,并且一旦找不到元素就可以停止,我们可以按如下方式调整循环(仍然假设我们希望按照输入文件中出现的顺序保留元素):

i=0
while true; do
    ((++i))
    nl sourcefile | tac | grep -m 1 "\$element_($i)" || break
done | sort -n | cut -f 2 > resultfile

这使用递增计数器而不是预定序列。如果管道的退出状态不为零,即 grep 找不到该元素,我们将退出循环。

© www.soinside.com 2019 - 2024. All rights reserved.