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
。否则,使用 awk
或 perl
.
$ 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;;;;
$
我需要通过检查系统中的所有 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
。否则,使用 awk
或 perl
.
$ 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;;;;
$