이 단일 라이너는 사전 정렬없이 텍스트 입력에서 중복 라인을 제거합니다.
예를 들면 다음과 같습니다.
$ 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++;