0

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

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

4

1 回答 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 找不到元素,我们退出循环。

于 2016-02-26T14:44:33.110 回答