bash:如果字段相等,则为grep行

问题描述

我需要通过检查系统中的所有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[$1,$2]++} END {for(i in col) print i,col[i]}'

但是我错过了所有列之间的比较。

解决方法

您可以使用grep命令:

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

如果输入仅包含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 '[^;]*(;[^;]*)\1+' f1 > t1
real    0m44.815s

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

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

$ time LC_ALL=C awk -F ';' '{for (i=3; i<=NF; i++) if ($i != $2) 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
,

使用awk的非正则表达式方法:

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

另一个awk

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

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...