我有一个字符串 tstArr2 ,其中包含以下内容
'3 5 8'
现在在 awk 中我想解析一个平面文件
test my array which array is better array
INDIA USA SA NZ AUS ARG GER BRA
US AUS INDIA ENG NZ SRI PAK WI BAN NED IRE
仅在这些编号的列中。我尝试了以下方法
awk -vA="$tstArr2" 'BEGIN{split(A,B," ");} {if(NR>1){for(i=1; i<= length(B); i++){printf "%s ",B[i]}}print " "}' testUnix3.txt
但它说
awk: Cannot read the value of B. It is an array name.
The input line number is 2. The file is testUnix3.txt.
The source line number is 1.
我缺少什么?如果我尝试以下操作
awk -vA="$tstArr2" 'BEGIN{split(A,B," ");} {if(NR>1){for(i in B){printf "%s ",$B[i]}}print " "}' testUnix3.txt
它打印输出,但它们不按顺序排列。我希望它们井然有序。请解释。期望的输出:
SA AUS BRA
INDIA NZ WI
答案1
POSIX 定义长度inawk
是一个字符串函数,参数作为字符串。使用length
数组作为参数是未指定的行为。
在一些awk
类似的实现中gawk(版本 >= 3.1.6),OS X 版本的 AWK,您可以使用length
数组作为参数,它将返回数组中的元素数量。
数组 inawk
是关联数组,循环关联数组并不能保证任何顺序。在这种情况下,您可以利用分裂函数,它返回字段的数量以获取数组的数量元素。
POSIXly,你可以尝试:
$ awk -vA="$tstArr2" '
BEGIN{n = split(A,B," ");}
{
if(NR > 1) {
for(i = 1;i <= n;i++) {
printf "%s ",$B[i];
}
}
print " ";
}
' file
SA AUS BRA
INDIA NZ WI
答案2
(对于非 GNU awk,请参阅 @cuonglm 的回答。)
以此作为测试文件:
$ cat testUnix3.txt
test my array which array is better array
INDIA USA SA NZ AUS ARG GER BRA
US AUS INDIA ENG NZ SRI PAK WI BAN NED IRE
此代码选择第 3、5 和 8 列:
$ tstArr2='3 5 8'
$ awk -vA="$tstArr2" 'BEGIN{split(A,B," ");} NR>1{for(i=1; i<= length(B); i++) printf "%s ",$B[i]; print "";}' testUnix3.txt
SA AUS BRA
INDIA NZ WI
以上是用 GNU 测试的awk
。
awk
循环和顺序
awk
具有关联数组。作为格雷莫尔 awk 教程 解释:
关联数组有一个小问题,特别是当您使用为了输出每个元素的命令:您无法控制输出的顺序。
for(i in B)
这就是为什么您引用的其他使用循环的代码有时可能会乱序打印列的原因。
GNU awk 有一个扩展来解决这个问题:
$ gawk -vA="$tstArr2" 'BEGIN{split(A,B," "); PROCINFO["sorted_in"]="@ind_num_asc"} {if(NR>1){for(i in B){printf "%s ",$B[i]}print " "}}' testUnix3.txt
SA AUS BRA
INDIA NZ WI
通过设置PROCINFO["sorted_in"]="@ind_num_asc"
,索引将按数字升序循环。这个 GNU 扩展已记录在案这里。
答案3
使用如此强大的仪器来awk
完成如此简单的任务会产生很大的开销:
tstArr2='3,5,8'
tail -n+2 testUnix3.txt | cut -d' ' -f"$tstArr2"