显示多个文件中重复行的位置

显示多个文件中重复行的位置

我有两个文件:

#a.txt

11
22
33
44
55
11

# b.txt

55 
66 
77 
88 
99 
11

我执行这个命令来打印两个文件中的重复行:sort *.txt | uniq -D 并且它输出:

11
11
11
55
55

我希望它输出准确的位置;例如,对于输出的第 1 行,它应该说明它来自哪里:第 1 行,文件 a.txt即一种差异。

请问我该如何做到这一点?

答案1

总结

你可以做这样的事情:

file_expr="*.txt"; sort $file_expr | sed 's/^\s*//; s/\s*$//; /^\s*$/d' | uniq -d | while read dup_line; do grep -Hn "^\s*$dup_line\s*$" $file_expr; done| sort -t: -k3 -k1,2 | awk -F: '{ file=$1; line=$2; $1=$2=""; gsub(/(^[ \t]+)|([ \t]+$)/,"",$0); if (prev != "" && prev != $0) printf ("\n"); printf ("\033[0;33m%s (line %s)\033[0m: %s\n", file, line, $0); prev=$0; }'

结果:

a.txt (line 3): 11
a.txt (line 8): 11
b.txt (line 8): 11

a.txt (line 7): 55
b.txt (line 3): 55

改变变量的内容file_expr来改变受影响的文件


解释

我使用sed命令来修剪全部尾随领导空格和删除空行,使得uniq -d仅获取真正重复的行......

然后我环形重复的行(每匹配一次打印一行)并grep使用标志将它们放入文件中-n打印文件线) 和-H总是显示文件名)。表达式^\s*$dup_line\s*$放入grep使其匹配全线(例如“qwerty11uiop”不匹配)。

正如你所看到的,它可以使用文件通配符...

file_expr="*.txt"; sort $file_expr | sed 's/^\s*//; s/\s*$//; /^\s*$/d' | uniq -d | while read dup_line; do grep -Hn "^\s*$dup_line\s*$" $file_expr; done

结果:

a.txt:3:11  
a.txt:8:11  
b.txt:8:11  
a.txt:7:55  
b.txt:3:55  

... 和文字文件名..

file_expr="a.txt b.txt"; sort $file_expr | sed 's/^\s*//; s/\s*$//; /^\s*$/d' | uniq -d | while read dup_line; do grep -Hn "^\s*$dup_line\s*$" $file_expr; done

结果:

a.txt:3:11
a.txt:8:11
b.txt:8:11
a.txt:7:55
b.txt:3:55

小调整

然后我稍微调整了一下,让它看起来更舒服的... 像这样:

file_expr="a.txt b.txt"; sort $file_expr | sed 's/^\s*//; s/\s*$//; /^\s*$/d' | uniq -d | while read dup_line; do grep -Hn "^\s*$dup_line\s*$" $file_expr; done| sort -t: -k3 -k1,2 | awk -F: '{ file=$1; line=$2; $1=$2=""; gsub(/(^[ \t]+)|([ \t]+$)/,"",$0); if (prev != "" && prev != $0) printf ("\n"); printf ("\033[0;33m%s (line %s)\033[0m: %s\n", file, line, $0); prev=$0; }'

结果:

a.txt (line 3): 11
a.txt (line 8): 11
b.txt (line 8): 11

a.txt (line 7): 55
b.txt (line 3): 55

在最后一个视图中,一切都更加“人性化”,重复项首先按结果分组,然后按文件分组(您可以看到结果a.txt都在一起),因此更容易理解。

文件名和行现在为黄色(\033[0;33m),以区别于实际行中的文本,以防出现多行(请原谅这个双关语)重复的情况

答案2

由于您的示例中的b.txt文件中含有空格,因此您可以使用它awk来抓取空格前的字符。

将我上面的评论转换为此处的答案。您可以使用grep -n显示行号及其来源文件。还要添加一个uniq命令,以便当 grep 循环查找重复项时,它不会经过 3 个 11 和 2 个 55。

简单示例:

sort *.txt | awk '{print $1}' | uniq -D 
11
11
11
55
55

通过添加第二个,uniq输出仅为:

11
55

现在我们可以添加grepwhile循环。 grep将显示每个出现的次数以及它们位于哪个文件中。

sort *.txt | awk '{print $1}' | uniq -D | uniq | while read num; do grep -n $num *.txt; done

例子:

$ sort *.txt | awk '{print $1}' | uniq -D | uniq | while read num; do grep -n $num *.txt; done
a.txt:2:11
a.txt:7:11
b.txt:7:11
a.txt:6:55
b.txt:2:55 

相关内容