为什么 awk split() 使第一个字段成为数组中的最后一个元素?

Rhy*_*oid 1 awk

我可能在这里遗漏了一些非常简单的东西,但是当我说

echo 'The quick brown fox jumped over the lazy dog.' | \
    awk '{
        split($0, WORDS, " ");
        for ( WORD in WORDS ) {
            print $WORD;
        }
    }'
Run Code Online (Sandbox Code Playgroud)

我得到这个回报:

quick
brown
fox
jumped
over
the
lazy
dog.
The
Run Code Online (Sandbox Code Playgroud)

为什么第一个字最后打印?

$ awk --version
awk version 20070501
Run Code Online (Sandbox Code Playgroud)

cuo*_*glm 7

首先,for (i in array)awkyield 数组的索引,而不是数组元素。所以你得到了你访问的结果$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
Run Code Online (Sandbox Code Playgroud)

您可以看到在访问变量时获得了数组索引WORD


对于您的问题,POSIX 定义了遍历awk数组的循环,以未指定的顺序生成数组索引:

for(数组中的变量)

它将迭代,以未指定的顺序将数组的每个索引分配给变量 。

所以由实现来定义如何遍历数组。

在我的系统中进行的快速测试表明,gawkmawk以递增顺序循环:

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
Run Code Online (Sandbox Code Playgroud)

(使用 GNU sed,您需要sed -u 1q


ter*_*don 5

您不是在打印数组的元素,而是按顺序打印字段。在 中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
Run Code Online (Sandbox Code Playgroud)

你追求的是:

$ 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.
Run Code Online (Sandbox Code Playgroud)

其中,在 GNU 中awk,相当于:

 $ echo 'The quick brown fox jumped over the lazy dog.' |     awk '{
            for (i=1; i<=NF;i++){
            print $i
        }
    }'
Run Code Online (Sandbox Code Playgroud)

虽然gawk(GNU awk)split将按照找到的顺序对数组进行排序(如上所示),但其他实现不会这样做,正如 cuonglm 在他的回答中所解释的那样。因此,split您可以设置字段分隔符和 letawk来进行拆分,而不是使用。在您的示例中,由于分隔符是一个空格,因此没有必要,但以下是其他情况下的操作方法:

 $ 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.
Run Code Online (Sandbox Code Playgroud)