awk Split()が最初のフィールドを配列の最後の要素にするのはなぜですか?

awk Split()が最初のフィールドを配列の最後の要素にするのはなぜですか?

おそらくここで非常に簡単なものを見逃しているかもしれませんが、

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を使用するsedsed -u 1q

答え2

配列の要素を印刷する代わりに、フィールドを順次印刷します。では変数の前に、つまりフィールドがawk付いていません。$したがって、$aフィールドに保存されているすべての数字が印刷されますa。たとえば、変数を印刷するにはnoが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フィールド区切り文字を設定し、awk代わりにletを使用して分割を実行できます。あなたの例では、区切り文字は空白なので必要ありませんが、他の場合は区切り文字を使用する方法は次のとおりです。

 $ 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を使用すると制御できますが)。

関連情報