Hai*_* Vu 18
在awk脚本中查看我的评论
$ cat data.txt
John Thomas;jd;301
Julie Andrews;jand;109
Alex Tremble;atrem;415
John Tomas;jd;302
Alex Trebe;atrem;416
$ cat dup.awk
BEGIN { FS = ";" }
{
# Keep count of the fields in second column
count[$2]++;
# Save the line the first time we encounter a unique field
if (count[$2] == 1)
first[$2] = $0;
# If we encounter the field for the second time, print the
# previously saved line
if (count[$2] == 2)
print first[$2];
# From the second time onward. always print because the field is
# duplicated
if (count[$2] > 1)
print
}
Run Code Online (Sandbox Code Playgroud)
示例输出:
$ sort -t ';' -k 2 data.txt | awk -f dup.awk
John Thomas;jd;301
John Tomas;jd;302
Alex Tremble;atrem;415
Alex Trebe;atrem;416
Run Code Online (Sandbox Code Playgroud)
这是我的解决方案#2:
awk -F';' '{print $2}' data.txt |sort|uniq -d|grep -F -f - data.txt
Run Code Online (Sandbox Code Playgroud)
这个解决方案的优点是它保留了行顺序,代价是一起使用许多工具(awk,sort,uniq和fgrep).
awk命令打印出第二个字段,然后对其输出进行排序.接下来,uniq -d命令选出重复的字符串.此时,标准输出包含重复的第二个字段的列表,每行一个.然后我们将该列表输入fgrep.' -f - '标志告诉fgrep从标准输入中查找这些字符串.
是的,你可以用命令行全力以赴.我喜欢第二种解决方案,更好地用于锻炼许多工具和更清晰的逻辑(至少对我而言).缺点是工具的数量和可能使用的内存.此外,第二种解决方案是低效的,因为它扫描数据文件两次:第一次使用awk命令,第二次使用fgrep命令.这种考虑仅在输入文件很大时才有意义.
有一个复杂的awk脚本.
awk 'BEGIN { FS=";" } { c[$2]++; l[$2,c[$2]]=$0 } END { for (i in c) { if (c[i] > 1) for (j = 1; j <= c[i]; j++) print l[i,j] } }' file.txt
Run Code Online (Sandbox Code Playgroud)
它的工作原理是保留第二个字段中每个值的所有出现的计数器,以及具有该值的行,然后打印出计数器大于1的行.
用$2您需要的任何字段编号替换所有实例,file.txt最后用您的文件名替换.
grep 可以做到这一点,但我猜你使用awk(在某些系统上又名 gawk)会更容易。
用于满足您的需求的有效链/脚本取决于一些额外的信息。例如,输入文件是否易于排序、输入有多大(或者更确切地说是巨大还是流)...
假设输入已排序(无论是最初的还是通过排序的管道),awk 脚本看起来像这样:(注意未经测试)
检查 Jonathan Leffler 或 Hai Vu 提供的解决方案,了解无需预排序要求即可实现相同目的的方法。
#!/usr/bin/awk
# *** Simple AWK script to output duplicate lines found in input ***
# Assume input is sorted on fields
BEGIN {
FS = ";"; #delimiter
dupCtr = 0; # number of duplicate _instances_
dupLinesCtr = 0; # total number of duplicate lines
firstInSeries = 1; #used to detect if this is first in series
prevLine = "";
prevCol2 = ""; # use another string in case empty field is valid
}
{
if ($2 == prevCol2) {
if (firstInSeries == 1) {
firstInSeries = 0;
dupCtr++;
dupLinesCtr++;
print prevLine
}
dupLinesCtr++;
print $0
}
else
firstInSeries = 1
prevCol2 = $2
prevLine = $0
}
END { #optional display of counts etc.
print "*********"
print "Total duplicate instances = " iHits " Total lines = " NR;
}
Run Code Online (Sandbox Code Playgroud)