使用 AWK 基于列表过滤数据集

使用 AWK 基于列表过滤数据集

我想根据条件从数据帧中过滤行(如果它们存在于列表中)。到目前为止我已经尝试过这个事情。但我得到了意想不到的结果。数据正在被复制,但我无法理解它

#!/bin/bash
arr_country=(AL AD AM AT BY BE BA BG CH)
for element in "${arr_country[@]}"
do
awk -F '\t' '{if($1==$element){print}}'   abc.txt >>xyz.txt
done
echo
echo "Data Transferred"

示例数据集包含有关不同国家/地区的信息,第一列代表国家/地区名称。我想根据给定的数组对数据集进行子集化。

答案1

element不是awk变量。

要将 shell 变量的值导入到awk脚本中,您可以使用

awk -v variable="$value" '{ script goes here }'

在上面的示例中,调用的变量variable将获取名为 的 shell 变量的值value。您可以variableawk脚本中使用而不用前缀$.

请注意,如果您为变量添加前缀$in awk,则假定该变量的值是正整数,并且它引用当前输入记录中的特定字段。$element例如,该表达式将为您提供字段编号的值element(就像为$1您提供第一个字段的值并$NF为您提供最后一个字段的值,其中NF是表示当前记录中字段数量的内置变量) 。

如果element在代码中未设置awk$element则将扩展为$0完整行。如果第一个制表符分隔字段是该行中唯一的内容,那么您的代码将打印整行。

您的awk脚本也可以缩短为

awk -F '\t' -v e="$element" '$1 == e'

或者,您可以将整个内容替换为

arr_country=(AL AD AM AT BY BE BA BG CH)

( IFS='|'; grep -E "^(${arr_country[*]})\>" ) <abc.txt >xyz.txt

或者,

grep -E '^(AL|AD|AM|AT|BY|BE|BA|BG|CH)\>' <abc.txt >xyz.txt

参数${arr_country[*]}替换将扩展为单个字符串,该字符串由数组的值组成,并以 的第一个字符分隔$IFS。这将创建一个与上面显示的第二个相同的正则表达式grep\>将匹配单词末尾的零宽度空格(以便^AA\>匹配AA行首,但不匹配AAA)。

唯一的区别是,与 的 shell 循环解决方案相比,结果的顺序可能不同awk


消除 shell 循环的不同方法(假设 的默认值$IFS):

arr_country=(AL AD AM AT BY BE BA BG CH)

awk -v c="${arr_country[*]}" -F '\t' '
    BEGIN { n=split(c,a," "); for (i=1;i<=n;++i) country[a[i]] }
    $1 in country' <abc.txt >xyz.txt

在这里,我们将 的元素arr_country作为空格分隔的字符串赋予awk变量 中的代码c。在开始从输入读取之前,c字符串被分成几部分,并且每部分都被制作成关联数组中的一个键country。如果第一个字段是该数组中的键,则打印该行。

相关内容