我有如下所示的巨大文件。如果第二列的值为 60、30 等,我想删除这些行,所有这些值都将从逗号分隔的另一个文件中获取。
position_id risk_measure_id Scenario_id value_usd
1 60 0 300.8
2 30 0 400.6
3 45 90 300.7
4 60 0 200.9
5 30 9 400.8
6 60 10 4000.9
8 20 0 5000.9
我可以使用下面的awk
命令来实现它,但如果我有多个值需要排除,是否有任何简单的方法。
$ awk '{ if ($2!=60 && $2!=25 && $2!=30) print $0}' test.txt
position_id risk_measure_id Scenario_id value_usd
3 45 90 300.7
8 20 0 5000.9
答案1
将您的值放入另一个文件中:
values
:
60
25
30
然后将它们读入数组中awk
:
awk 'FNR == NR {arr[$0] = 1; next} !($2 in arr)' values test.txt
FNR == NR
在读取第一个文件时成立,因此第一个块仅在读取值时执行。由于next
,因此!($2 in arr)
仅对第二个文件执行。
答案2
您的命令可以进一步简化 - 您不需要if
语句和代码块,因为 awk 可以使用代码块前面的匹配条件打印行。如果您只想打印行,则可以完全跳过代码块:
$ awk '$2!=60 && $2!=25 && $2 != 30' input.txt
position_id risk_measure_id Scenario_id value_usd
3 45 90 300.7
8 20 0 5000.9
替代解决方案是使用数组:
awk -v values="60 30 25" 'BEGIN{split(values,array)};{ flag=0; for(val in array) if (array[val] == $2) flag=1; if (flag==0) print }' input.txt
实际情况是,我们创建一个包含所有所需值的字符串,并以空格分隔。在 BEGIN 语句中,我们将其分解为数组。主代码块在读取每一行时将标志变量设置为 0,然后我们循环遍历数组中的所有值并检查字段 #2 是否与数组中的任何内容匹配。如果匹配,我们将标志设置为 1。循环退出后,我们查看循环是否找到任何内容并设置标志,如果没有找到 - 打印该行。
此方法的较短版本是,如果找到排除值,则使用next
命令中断循环。这样,print
只有未找到排除值时才会达到函数:
awk -v values="60 30 25" 'BEGIN{split(values,array)};{for(val in array) if (array[val] == $2) next; print}' input.txt