Grep 和 find 获取多个文件中的最后一个匹配项

Grep 和 find 获取多个文件中的最后一个匹配项

假设两个文件具有以下内容:

$ cat ttest1.txt 
x = 1
x = 3
y = 5
$ cat ttest2.txt 
x = 4
x = 10
y = 3

我想递归地 grep 文件x并打印每个文件中的最后一个实例。所以,期望的输出是

ttest1.txt:x = 3
ttest2.txt:x = 10

以下grep和的组合tail适用于一个文件,但不适用于多个文件。

$ grep x ttest1.txt 
x = 1
x = 3
$ grep x ttest1.txt | tail -n 1
x = 3
$ grep -r x ttest* | tail -n 1
ttest2.txt:x = 10

我该如何解决这个问题?

答案1

当你这样做时

grep -r x ttest* 

你得到一个流

ttest1.txt:x = 1
ttest1.txt:x = 3
ttest2.txt:x = 4
ttest2.txt:x = 10

如果你tail -1这样做,你就会得到ttest2.txt:x = 10.这正如预期的那样。

但是您希望grep | tail在每个单独的文件上完成组合,而不是在合并的流上完成。所以:对每个单独的文件执行此操作。

for f in ttest* ; do
    grep x "$f" | tail -n 1
done

答案2

使用awk,您可以使用正则表达式字符串(请参阅动态正则表达式),记住每个输入文件的最后一个匹配并打印它:

$ awk -v regex="x" 'FNR==1 && m!=""{print m;m=""} 
        $0 ~ regex{m=FILENAME ":" $0}
        END{if (m!="")print m}' ttest*
ttest1.txt:x = 3
ttest2.txt:x = 10

递归地与 结合find

$ find . -name 'ttest*' -type f -exec awk -v regex="x" '
        FNR==1 && m!=""{print m;m=""}
        $0 ~ regex{m=FILENAME ":" $0}
        END{if (m!="")print m}' {} +
./ttest1.txt:x = 3
./ttest2.txt:x = 10

答案3

使用 GNU sed:

sed -sn '/x/h; $ { x; F; p; }' ttest*

输出:

ttest1.txt
x = 3
ttest2.txt
x = 10

paste -d: - -如果您希望结果在一行中,请通过此选项。如果您不想从不包含-change 命令x后包含检查的文件中输出x,例如:{ x; /./ { F; p; z; }; }

答案4

这是一种方法:

grep  x <yourpath>*  | tac | awk  'BEGIN{FS=":"};seen!=$1{print $0;seen=$1}'

tac 反转 grep 结果以准备 awk 操作,然后仅打印每个文件中的第一个匹配项

相关内容