我可能在这里遗漏了一些非常简单的东西,但是当我说
echo 'The quick brown fox jumped over the lazy dog.' | \
awk '{
split($0, WORDS, " ");
for ( WORD in WORDS ) {
print $WORD;
}
}'
我得到这样的回报:
quick
brown
fox
jumped
over
the
lazy
dog.
The
为什么第一个字最后打印?
$ awk --version
awk version 20070501
答案1
首先, yieldfor (i in array)
中的awk
是数组的索引,而不是数组元素。所以你得到了像你访问的结果$1
。$2
....$NF
echo 'The quick brown fox jumped over the lazy dog.' | \
awk '{
split($0, WORDS, " ");
for ( WORD in WORDS ) {
print WORD;
}
}'
2
3
4
5
6
7
8
9
1
您可以看到访问变量时获得了数组索引WORD
。
对于你的问题,POSIX 定义了通过awk
数组循环产生数组索引未指定顺序:
for(数组中的变量)
它将迭代,将数组的每个索引分配给变量 未指定顺序。
所以由实现来定义如何来遍历数组。
我的系统中的快速测试表明了这一点,gawk
并mawk
以递增顺序循环:
for AWK in gawk mawk /usr/5bin/[on]awk /usr/5bin/posix/awk; do
printf '==%s==\n' "$AWK"
echo 'The quick brown fox jumped over the lazy dog.' |
"$AWK" '{
split($0, WORDS, " ")
for (WORD in WORDS) {
print WORD;
}
}' | { sed 1q; tail -n1 }
done
==awk==
1
9
==mawk==
1
9
==/usr/5bin/nawk==
2
1
==/usr/5bin/oawk==
2
1
==/usr/5bin/posix/awk==
2
1
(使用GNU sed
,你需要sed -u 1q
)
答案2
您不是打印数组的元素,而是按顺序打印字段。在 中awk
,变量没有前缀 a $
,那就是字段。因此,$a
将打印存储在 中的任何数字的字段a
。要打印变量,例如foo
,您需要print foo
, 不$
。
当您迭代数组时awk
,您正在迭代数组的索引:
$ echo 'The quick brown fox jumped over the lazy dog.' | awk '{
split($0, WORDS, " ");
for ( WORD in WORDS ) {
print WORD;
}
}'
1
2
3
4
5
6
7
8
9
你所追求的是:
$ echo 'The quick brown fox jumped over the lazy dog.' | awk '{
split($0, WORDS, " ");
for ( WORD in WORDS ) {
print WORDS[WORD];
}
}'
The
quick
brown
fox
jumped
over
the
lazy
dog.
在 GNU 中awk
,这相当于:
$ echo 'The quick brown fox jumped over the lazy dog.' | awk '{
for (i=1; i<=NF;i++){
print $i
}
}'
虽然gawk
(GNU awk
)split
会按照找到的顺序对数组进行排序(如上所示),但其他实现不会这样做,正如 cuonglm 在他的答案中解释的那样。因此,split
您可以设置字段分隔符并使用 let来代替使用awk
来进行拆分。在您的示例中,不需要,因为分隔符是空格,但以下是其他情况下的操作方法:
$ echo 'The-quick-brown-fox-jumped-over-the-lazy-dog.' |
awk -F"-" '{
for(i=1;i<=NF;i++){
print $i
}
}'
The
quick
brown
fox
jumped
over
the
lazy
dog.
答案3
$1
忽略在您的示例中,您可以(应该)只打印每个字段、$2
等的事实,split
返回数组中的元素数量,因此要按照它们出现的顺序循环遍历它们,您可以使用如下所示的内容:
echo 'The quick brown fox jumped over the lazy dog.' | \
awk '{
n = split($0, WORDS, " ");
for (i = 1; i <= n; ++i) {
print WORDS[i];
}
}'
正如其他人提到的,使用时遍历数组的顺序for (indx in array)
是未指定的(尽管如果您使用 GNU awk,则可以控制它)。