我想根据多列中的匹配项丢弃行。对于第 1 列中的所有匹配项,请检查相应的第 2 列。仅当第 2 列的所有条目都相同时,才丢弃所有行。如果第 2 列中的一个条目不同,则保留所有行。
例子:
丢弃前 3 行,因为 Bob 的每个第 2 列条目都是相同的。但是,请保留其余 4 行,因为第 2 列中至少有一个条目与 Jan 不同:
Bob Blue
Bob Blue
Bob Blue
Jan Red
Jan Red
Jan Green
Jan Red
这是使用GNU awk
. 像这样运行:
awk -f script.awk file.txt{,}
内容script.awk
:
FNR==NR {
array[$0]++
next
}
{
counter = 0
for (i in array) {
split(i, holder, FS)
if (holder[1] == $1) {
counter++
}
}
if (counter >= 2) {
print
}
}
结果:
Jan Red
Jan Red
Jan Green
Jan Red
或者,这是单线:
awk 'FNR==NR { array[$0]++; next } { counter = 0; for (i in array) { split(i, holder, FS); if (holder[1] == $1) counter++ } if (counter >= 2) print } ' file.txt{,}
这可能对您有用(尽管它是 GNU sed):
sed ':a;$!N;/^\(\S*\s\).*\n\1/{s/\n/\x01/;ba};h;x;s/\n.*//;s/^/\x01/;/^\(\x01[^\x01]\+\)\(\1\)\+$/{x;D};s/.//;s/\x01/\n/gp;x;D' file
解释:
:a
循环标记$!N
除非它是最后一行,否则将换行符和下一行附加到模式空间 (PS)/^\S*\s).*\n\1/{s/\n/\x01/;ba}
将以相同键开头的所有行组成一行,用十六进制代码替换换行符01
h
将当前 PS 存储在保持空间 (HS) 中x
用 HS 切换 PSs/\n.*//
删除附加的最后一行(这不匹配)s/^/\x01/
在 HS 的开头添加一个十六进制代码01
(这是一个用于匹配目的的虚构换行符。/^\(\x01[^\x01]\+\)\(\1\)\+$/{x;D}
对于那些相同的行,即没有例外,用 PS 切换 HS 并删除这些行并开始下一次迭代。s/.//;s/\x01/\n/gp;x;D'
那些确实有异常的行,删除01
添加到前面的添加的十六进制代码,用换行符替换所有其他此类代码并打印这些行。然后用 PS 切换 HS 并删除到第一个换行符并开始下一次迭代。三个简单的步骤:
sort -u temp | nawk '{a[$1]++}END{for(i in a)print i,a[i]}' > temp_file
nawk 'FNR==NR{a[$1]=$2;next}{if(($1 in a) && a[$1]>1)print $0}' temp_file your_file
rm -rf tempfile
您可以将这些步骤合并到一个 shell 脚本中,然后执行它
如果您的输入位于名为“test.txt”的文本文件中,您可以运行它:
cat test.txt | grep ^`cat test.txt | sort -u | awk 'BEGIN{split("", aux, "");ok="";} {if ($1 in aux){if (length(ok) > 0){ok=ok"\|"$1;}else{ok=$1;}}aux[$1]="";} END{print ok;}' -`
可以一步步执行来理解命令,也可以问我(AWK部分有点复杂)。
这样,输出为:
Jan Red
Jan Red
Jan Green
Jan Red
编辑:我忘了将反斜杠添加到“|” grep 的 OR ;-)
KEY_STRINGS="`sort file | uniq | awk '{print$1}' | uniq -d`"
awk -vkeys="$KEY_STRINGS" '{if(keys~/$1/)print$0}' file
我相信这个脚本会更容易理解。