所以我有一个以下格式的输入文件:
Hello\tWorld
然后我可以使用
awk -F"\t" '!seen[tolower($1)]++'
根据第一列删除重复行,但是我将如何在该语句中设置条件?也就是说,如果字符串使用超过 5 次,则仅删除重复或所有行?
输入示例:
Hello World
Hello World
Hello World
Hello World
Hello World
New Example
Hello World
因此,在上面的示例中,column1 存在超过 5 次,因此预期输出将是
Hello World
New Example
或者如果我们想完全删除该特定行,
New Example
答案1
表达式是一个布尔值,测试数组条目是否第一次存在。它用 !来反转条件。但它继续计数。
只需适应测试即可。这拒绝打印第 6 版及更高版本。
awk -F"\t" '++seen[tolower($1)] <= 5'
答案2
在这两个示例中,输入文件都被读取两次。在第一步中,对第一列进行计数,在第二步中,打印当前行并将其与计数进行比较。
如果第一列出现超过五次,则打印第一次出现的位置:
awk -F'\t' ' FNR==NR{ seen[tolower($1)]++; next } seen[tolower($1)] seen[tolower($1)]>5{ delete seen[tolower($1)] } ' file file
仅当数组 ( ) 中存在第一列时才打印当前行
seen[tolower($1)]
。如果出现超过五次,则将其从数组中删除。如果第一列出现超过五次,请删除该行:
awk -F'\t' ' FNR==NR{ seen[tolower($1)]++; next } seen[tolower($1)]<=5 ' file file
仅当列数小于或等于五时才打印当前行。
答案3
通过将整个文件存储在数组中,可以在不读取文件两次的情况下完成整个事情,这意味着它将在管道中工作。我没有比较额外的复杂性是否比读取文件两次更好,但它每秒处理大约 275,000 行。我经常使用高达 400 MB 的 awk 数组,因此数据量应该不是问题。
这显示了输入文件的大小和密钥数。
Paul---) wc 53.txt
100008 187520 1100108 53.txt
Paul---) cut -f1 53.txt | sort | uniq -c
12500 Can
12500 Care
12500 If
12500 Major
12500 Minor
12500 Not
5 Oak
12500 Sample
1 Spruce
2 Willow
12500 With
这显示了执行和时间。还需要进行一些调试,以确认输入中数据的传播、密钥与行其余部分的分离以及原始序列的保留。 Cat 用于强制执行管道输入。
Paul---) time cat 53.txt | ./5fold
Ln 5590 Num 5 Key :Oak: Oak Fifth
Ln 8654 Num 2 Key :Willow: Willow Pattern China
Ln 13427 Num 1 Key :Spruce: Spruce Only One
Ln 65309 Num 5 Key :Oak: Oak Fourth
Ln 70988 Num 5 Key :Oak: Oak Third
Ln 83982 Num 5 Key :Oak: Oak Second
Ln 87439 Num 5 Key :Oak: Oak First
Ln 99977 Num 2 Key :Willow: Willow Weep for Me
real 0m0.359s
user 0m0.324s
sys 0m0.048s
这是经过测试的代码。
#! /bin/bash
AWK='''
BEGIN { FS = "\t"; nMax = 5; }
function List (Local, j) {
for (j = 1; j in X; ++j) {
if (N[K[j]] <= nMax)
printf ("Ln %6d Num %d Key :%s: %s\n", j, N[K[j]], K[j], X[j]);
}
}
{ ++N[$1]; K[NR] = $1; X[NR] = $0; }
END { List( ); }
'''
awk -f <( echo "${AWK}" )