awk ‘! a [$ 0] ++’는 어떻게 작동합니까? 다음과 같습니다. awk ‘!_[$0]++’ _Perl과 같이 awk에서 특별한

이 단일 라이너는 사전 정렬없이 텍스트 입력에서 중복 라인을 제거합니다.

예를 들면 다음과 같습니다.

$ cat >f
q
w
e
w
r
$ awk '!a[$0]++' <f
q
w
e
r
$ 

인터넷에서 찾은 원래 코드는 다음과 같습니다.

awk '!_[$0]++'

_Perl과 같이 awk에서 특별한 의미를 갖기 위해 나에게 이것은 더 당혹 스럽지만 배열의 이름 일뿐이었습니다.

이제는 하나의 라이너 뒤에있는 논리를 이해합니다.
각 입력 줄은 해시 배열의 키로 사용되므로 완료되면 해시는 도착 순서대로 고유 한 줄을 포함합니다.

내가 배우고 싶은 것은이 표기법이 awk에 의해 어떻게 정확하게 해석되는지입니다. 예를 들어 뱅 기호 ( !)의 의미와이 코드 스 니펫의 다른 요소입니다.

어떻게 작동합니까?



답변

보자

 !a[$0]++

먼저

 a[$0]

우리는 a[$0]( a전체 입력 라인 ( $0)을 키로 사용 하여 배열) 의 값을 봅니다 .

존재하지 않는 경우 ( !테스트에서 부정은 참으로 평가됩니다)

 !a[$0]

입력 줄을 인쇄합니다 $0(기본 동작).

또한에 ( ++)을 추가 a[$0]하여 다음 !a[$0]에 false로 평가합니다.

좋아, 찾아라! 코드 골프를 봐야합니다!


답변

처리 과정은 다음과 같습니다.

  • a[$0]: $0연관 배열에서 키 값을보십시오 a. 존재하지 않는 경우 작성하십시오.

  • a[$0]++:의 값을 늘리고 a[$0]이전 값을 expression의 값으로 반환합니다. 경우 a[$0], 존재 반환하지 않습니다 0및 증가 a[$0]1( ++운영자 반환 숫자 값).

  • !a[$0]++: 표현의 가치를 부정합니다. 경우 a[$0]++반환 0, 전체 표현식이 true로 평가, 메이크업은 awk기본 작업을 수행 한 print $0. 그렇지 않으면 전체 표현식이 false로 평가되어 awk아무 것도 수행하지 않습니다.

참고 문헌 :

함께 gawk, 우리는 사용할 수 있습니다 (또는 dgawk awk --debug최신 버전) 디버그하는 gawk스크립트를. 먼저 다음과 같은 gawk스크립트를 작성하십시오 test.awk.

BEGIN {                                                                         
    a = 0;                                                                      
    !a++;                                                                       
}

그런 다음 다음을 실행하십시오.

dgawk -f test.awk

또는:

gawk --debug -f test.awk

디버거 콘솔에서 :

$ dgawk -f test.awk
dgawk> trace on
dgawk> watch a
Watchpoint 1: a
dgawk> run
Starting program: 
[     1:0x7fe59154cfe0] Op_rule             : [in_rule = BEGIN] [source_file = test.awk]
[     2:0x7fe59154bf80] Op_push_i           : 0 [PERM|NUMCUR|NUMBER]
[     2:0x7fe59154bf20] Op_store_var        : a [do_reference = FALSE]
[     3:0x7fe59154bf60] Op_push_lhs         : a [do_reference = TRUE]
Stopping in BEGIN ...
Watchpoint 1: a
  Old value: untyped variable
  New value: 0
main() at `test.awk':3
3           !a++;
dgawk> step
[     3:0x7fe59154bfc0] Op_postincrement    : 
[     3:0x7fe59154bf40] Op_not              : 
Watchpoint 1: a
  Old value: 0
  New value: 1
main() at `test.awk':3
3           !a++;
dgawk>

당신은 Op_postincrement전에 실행 된 것을 볼 수 있습니다 Op_not.

다음을 사용 si하거나 stepi대신 s또는 step보다 명확하게 볼 수도 있습니다 .

dgawk> si
[     3:0x7ff061ac1fc0] Op_postincrement    : 
3           !a++;
dgawk> si
[     3:0x7ff061ac1f40] Op_not              : 
Watchpoint 1: a
  Old value: 0
  New value: 1
main() at `test.awk':3
3           !a++;


답변