bash:如果字段相等则查找行

bash: grep row if fields are equal

我需要通过检查系统中的所有 CSV 文件来找到所有列中具有相同内容的所有行。示例:

MYCOL;1;2;3;4
MYCOL2;2;3;4;5
MYCOL3;1;1;1;1
MYCOL4;;;;

在我的示例中,我需要为 MYCOL3 和 MYCOL4 进行 grep,因为它们的所有列都具有相同的字段内容,即使没有内容也没关系。

我想到了这样的事情:

find / -name *.csv | xargs awk -F "," '{col[,]++} END {for(i in col) print i, col[i]}'

但我遗漏了所有列之间的比较。

您可以使用 grep 命令:

$ grep -xE '[^;]*(;[^;]*)+' ip.txt
MYCOL3;1;1;1;1
MYCOL4;;;;
  • -x 只匹配整行
  • [^;]* 第一个字段
  • (;[^;]*) 捕获 ; 后跟非 ; 字符(即第二个字段)
  • + 使用捕获的字段根据需要重复多次直到行尾

如果输入只有 ASCII 字符,您可以使用 LC_ALL=C grep <...> 来更快地获得结果。

如果你有 GNU grep,你可以使用 -r 选项和 --include= 选项而不是 find+grep

此外,使用 find <...> -exec grep <...> {} + 而不是 find + xargs


刚刚做了一个样本速度检查,这个正则表达式可能太糟糕了,无法与 BRE/ERE 一起使用。如果可用,请使用 grep -P。否则,使用 awkperl.

$ perl -0777 -ne 'print $_ x 1000000' ip.txt | shuf > f1
$ du -h f1
53M    f1

$ time LC_ALL=C grep -xE '[^;]*(;[^;]*)+' f1 > t1
real    0m44.815s

$ time LC_ALL=C grep -xP '[^;]*(;[^;]*)+' f1 > t2
real    0m0.507s

$ time perl -ne 'print if /^[^;]*(;[^;]*)+$/' f1 > t3
real    0m3.973s

$ time LC_ALL=C awk -F ';' '{for (i=3; i<=NF; i++) if ($i != ) next} 1' f1 > t4
real    0m2.728s

$ diff -sq t1 t2
Files t1 and t2 are identical
$ diff -sq t1 t3
Files t1 and t3 are identical
$ diff -sq t1 t4
Files t1 and t4 are identical

non-regex 方法使用 awk:

awk -F ';' '{for (i=3; i<=NF; i++) if ($i != ) next} 1' file
MYCOL3;1;1;1;1
MYCOL4;;;;

另一个 awk

$ awk -F";" -v OFS=";" ' { a=[=10=]; =""; c=split([=10=],ar,); if(length([=10=])==NF-1 || c==NF) print a } ' gipsy.txt
MYCOL3;1;1;1;1
MYCOL4;;;;
$