Linux에서 awk 스크립트 내에서 어떻게 정렬 할 수 있습니까?

다음 콘텐츠가 포함 된 fruit 파일이 있습니다.

Apples, 12 Pears, 50 Cheries, 7 Strawberries, 36 Oranges, 2 

파일의 숫자 데이터를 정렬하고 싶습니다.

for(i=1;i<=NF;i++)j+=$i;printf "Fruit %d%s, %d\n",NR,OFS,$1,j | sort -k 2 > "numbers"; j=0" 

awk 스크립트를 실행하기 위해 명령을 실행합니다. :

awk -f numbers fruit 

numbers 파일은 fruit와 같은 내용을 가지고 있지만 첫 번째와 두 번째 필드는 numbers 파일에 복사됩니다.

Comments

  • 왜 awk로 정렬해야합니까? Awk는 ' 기본 정렬 기능이 없습니다. 대신 출력을 정렬하지 않는 이유는 '입니까?
  • @ terdon GNU awk (내가 생각하기에 Linux의 기본 awk)에는 기본 정렬 기능이 있습니다.
  • @EdMorton은 그들의 마지막 질문 을 참조하세요. 어떤 맥락. 그리고 ' 정말 맞습니다! GNU awk에는 asort가 있습니다. 어떤 이유로 든 '하지 않았다고 맹세 할 수있었습니다. 감사! ' 전체 파일을 배열로 읽어 들인 다음 배열을 정렬해야하므로 그만한 가치가 있는지 확실하지 않으므로 출력을 정렬하는 것이 여전히 더 효율적일 수 있습니다. 하지만 ' 이것으로 충분합니다.
  • @terdon ' asort() 또한 훨씬 더 유용한 sorted_in를 사용하여 for (i in array)에 대한 순서를 간단히 정의 할 수 있습니다. 배열 요소를 방문하십시오.- gnu.org/software/gawk/manual/gawk.html#Controlling-Scanning.I 를 참조하십시오. 하지만이 문제에 대해 더 효율적입니다.
  • @EdMorton GNU awk는 데비안과 마찬가지로 기본값이 아닙니다. " mawk "가 기본값이며 ' " 정렬 " 내장 함수

답변

GNU awk는 배열 탐색 방법을 깔끔하게 제어 할 수있는 방법을 제공합니다. 배열 탐색 제어 스캔 제어

gawk -F", " " {fruit[$1] = $2} END { OFS = FS printf "\nordered by fruit name\n" PROCINFO["sorted_in"] = "@ind_str_asc" for (f in fruit) print f, fruit[f] printf "\nordered by number\n" PROCINFO["sorted_in"] = "@val_num_desc" for (f in fruit) print f, fruit[f] } " fruit 

출력

ordered by fruit name Apples, 12 Cheries, 7 Oranges, 2 Pears, 50 Strawberries, 36 ordered by number Pears, 50 Strawberries, 36 Apples, 12 Cheries, 7 Oranges, 2 

답변

실제로 awk의 print"sort" (따옴표 참고) :

$ awk "{print "Fruit",NR, $0 | "sort -k 2 -t, -rn"}" fruit Fruit 2 Pears, 50 Fruit 4 Strawberries, 36 Fruit 1 Apples, 12 Fruit 3 Cheries, 7 Fruit 5 Oranges, 2 

따라서 numbers에 작성하려면 다음을 수행 할 수 있습니다.

awk "{print "Fruit",NR, $0 | "sort -k 2 -t, -rn > numbers"}" fruit 

Awk를 약간 단순화했습니다. 여기에서 printf를 사용하거나 명시 적으로 인쇄 할 필요가 없습니다. OFS 어디에서나 변경하지 않기 때문입니다. I al 따라서 for(i=1;i<=NF;i++)j+=$i가 무엇을하는지 보지 마십시오. 이미 NR의 번호가 있으며 printfj를 사용하지 않았습니다.

코멘트

  • awk 내부에서 sort를 호출하는 대신 ' 간단하게 인쇄하는 것이 더 간단하고 효율적입니다. awk에서 awk 출력을 정렬하여 다음과 같이 파이프합니다. awk '{print ...}' fruit | sort ....
  • @EdMorton 아, 물론입니다!이 접근 방식은 절대 사용하지 않을 것입니다. 뭐 '가 요점인가요?하지만 이것이 OP가 요청한 것입니다 .
  • 정렬해야하는 요구 사항을 자주 찾습니다. gawk 내에서 ' 전체 출력을 정렬하고 싶지 않을 때입니다. 예를 들어 각 입력 파일에 대해 통계를 개별적으로 수집하고보고합니다. decorate / sort / clip 메소드를 사용하여 복잡한 데이터에서 간단한 키 만들기 (예 : 최대 등급의 측면 배열을 사용하여 전기 장비 과부하 순위 지정) 또한 외부 정렬은 디스크 작업 파일과 분할 / 병합 전략을 사용합니다. sort는 더 나은 방법을 사용할 수 있습니다.
  • @JoeSkora 당신은 awk에서 서브 쉘을 생성 할 필요가없고 ' 관련된 모든 버퍼링이 출력으로 이어지기를 바랍니다. 서브 쉘에서 awk 명령의 나머지 출력 이후에 stdout에 도달하기 전이 아니라 해당되는 경우 중간에 있습니다. awk '{print (NR>1), $0}' | sort -k1,1n -k2 | cut -d' ' -f2-
  • @EdMorton 조건부 좋은 아이디어를 인쇄하는 것을 좋아합니다. 마지막 부분은 더 단순화 할 수 있습니다. awk '{print (NR>1),$0}' | sort ... | cut -c3-.

답변

2002 년 SunOS nawk에 문제가 있습니다. 비 GNU awk 내에서 실행되는 세 가지 awk 구현이 포함 된 테스트 스크립트를 찾았습니다. 제 경우에는 좋지 않습니다. 에이전트없는 모니터링을 위해 ssh를 통해 작업을하고 있었고 외부 작업 파일이 라이브 서버에 너무 침입 적이기 때문입니다.

(b) qSort : 재귀 파티션 정렬입니다. 대용량 데이터의 경우 성능이 나쁘고> 2000 개 요소에 대해 mawk에서 스택이 중단됩니다. 그래도 쓰는 재미.

(c) hSort : 15 줄의 sort-in-situ 알고리즘. 이 힙은 인덱싱 알고리즘을 사용하여 바이너리 트리를 지원합니다 (Wikipedia 참조).

이 bash 스크립트에는 실제 정렬을 구현하는 awk 함수 hSort 및 hUp이 포함되어 있습니다. 하나의 액션 라인은 모든 입력을 배열에 넣고 END 블록은 hSort를 호출하고 결과를보고합니다.

입력 데이터는 “man bash”의 내용이며 한 번은 줄로, 다시는 단어로 표시됩니다. wc를 사용하여 손실 된 것이 없음을 증명하고 sort -c를 사용하여 출력이 정렬되었음을 증명합니다. 타이밍에는 읽기 및 인쇄 오버 헤드가 포함됩니다.

테스트 샷입니다.

Paul--) ./hSort Sorted 5251 elements. real 0m0.120s user 0m0.116s sys 0m0.004s 5251 44463 273728 hSort.raw sort: hSort.raw:2: disorder: 5251 44463 273728 hSort.srt Sorted 44463 elements. real 0m1.336s user 0m1.316s sys 0m0.008s 44463 44463 265333 hSort.raw sort: hSort.raw:3: disorder: Commands 44463 44463 265333 hSort.srt 

스크립트입니다. 즐기십시오!

#! /bin/bash export LC_ALL="C" #### Heapsort algorithm. function hSort { #:: (void) < text local AWK=""" #.. Construct the heap, then unfold it. function hSort (A, Local, n, j, e) { for (j in A) ++n; for (j = int (n / 2); j > 0; --j) hUp( j, A[j], n, A); for (j = n; j > 1; --j) { e = A[j]; A[j] = A[1]; hUp( 1, e, j - 1, A); } return (0 + n); } #.. Given an empty slot and its contents, pull any bigger elements up the tree. function hUp (j, e, n, V, Local, k) { while ((k = j + j) <= n) { if (k + 1 <= n && STX V[k] < STX V[k + 1]) ++k; if (STX e >= STX V[k]) break; V[j] = V[k]; j = k; } V[j] = e; } { U[++nU] = $0; } END { sz = hSort( U); printf ("\nSorted %s elements.\n", sz) | "cat 1>&2"; for (k = 1; k in U; ++k) print U[k]; } """ mawk -f <( printf "%s\n" "${AWK}" ) } #### Test Package Starts Here. function Test { time hSort < hSort.raw > hSort.srt for fn in hSort.{raw,srt}; do wc "${fn}"; LC_ALL="C" sort -c "${fn}"; done } AWK_LINE="{ sub (/^[ \011]+/, ""); print; }" AWK_WORD="{ for (f = 1; f <= NF; ++f) print $(f); }" #xxx : > hSort.raw; Test #.. Edge cases. #xxx echo "Hello" > hSort.raw; Test #xxx { echo "World"; echo "Hello"; } > hSort.raw; Test man bash | col -b | mawk "${AWK_LINE}" > hSort.raw; Test man bash | col -b | mawk "${AWK_WORD}" > hSort.raw; Test 

Answer

HeapSort는 적은 비용으로 표준 awk로 작성할 수 있습니다. 20 줄 이상. 눈부시게 빠르지는 않지만 언어에 상당히 잘 맞습니다.

댓글

  • 아, 안 했어요 ' 게시하지 마십시오. 나는 그 존재를 주장하고 독자를위한 연습 문제로 남겨 두었습니다.
  • 2020 년 1 월 9 일 코드와 테스트를 게시했습니다.

답글 남기기

이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다