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

Grep the last occurence of different elements in a big file

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

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 作为最大值,但它可以更少或更多。

按元素索引排序的输出

您可以告诉 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 找不到该元素,我们将退出循环。