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

우선, Yield for (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. 예를 들어 변수를 인쇄하려면 , 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를 사용하면 제어할 수 있지만).

관련 정보