파일에서 추출 및 재배열

파일에서 추출 및 재배열

일부 데이터를 추출하고 재정렬하려는 파일이 있습니다. 이전 파일에는 원본 데이터가 포함되어 있으며 이 파일은 입력입니다.

참조: cve, 2017-8962
서독: 45885
참조: cve, 2016-10033
참조: cve, 2016-10034
참조: cve, 2016-10045
참조: cve, 2016-10074
서독: 45917
참조: cve, 2017-8046
서독: 45976
참조: cve, 2018-6577
참조: cve, 2018-6578
서독: 46062

다음 파일은 필수 출력이 포함된 새 파일입니다.

참조: cve, 2017-8962
서독: 45885
참조: cve, 2016-10033
서독: 45917
참조: cve, 2016-10034
서독: 45917
참조: cve, 2016-10045
서독: 45917
참조: cve, 2016-10074
서독: 45917
참조: cve, 2017-8046
서독: 45976
참조: cve, 2018-6577
서독: 46062
참조: cve, 2018-6578
서독: 46062
.

참고: 예를 들어 sid:45917에는 4개의 참조가 있습니다(참조:cve,2016-10033 참조:cve,2016-10034 참조:cve,2016-10045 참조:cve,2016-10074). sid는 다른 sid에 추가됩니다(참고: sid 뒤에는 항상 참조가 옵니다.), 이렇게 중복된 블록이 있으므로 참조가 여러 개인 경우 새 파일 순서로 추가해야 합니다.

답변1

사용하시는 것 같으니나중에 sid:s (다중 references:다음에 단일 sids:=> 쌍 references:합계 sid:), 두 가지 솔루션.


해결 방법 1: 반전

간단히 tac명령을 사용하십시오 (그것은고양이입력 및 출력 역순(역순):tac input | awk | tac > output

awk 부분의 경우 s를 복사하면 됩니다 sid:.

gawk '/^sid:/{sid=$0};/^reference:/{print sid "\n" $0}'

해결 방법 2: 배열

도착하자마자 배열에 저장했다 reference:가 해당 항목을 만나면 뱉어냅니다.sid:

gawk 'BEGIN{r=0};/^reference:/{ref[r++]=$0};/^sid:/{for(n=0;n<r;n++){print ref[n] "\n" $0};r=0}' /tmp/test.txt

/^reference:/{ref[r++]=$0}: ref...로 시작하는 각 행에 대해 행을 배열에 저장하고 "r" 포인터를 다음 요소로 이동합니다.

/^sid:/{for(n=0;n<r;n++){print ref[n] "\n" $0};r=0}: 줄이 sid로 시작할 때마다 r 포인터(for...)까지 전체 배열을 반복하고, 각 요소에 대해 저장된 참조와 현재 줄(=sid)을 인쇄한 다음 r을 다시 시작 부분으로 재설정합니다. 다음 참조를 참조하여 다시 시작할 수 있습니다.

답변2

awk 'BEGIN { i=0; }
/^reference:/ { ref[i++] = $0; }
/^sid:/ { for(j=0; j<i; j++) { print ref[j]; print; } i=0; }' inputfile > outputfile

설명하다:

  • BEGIN { i=0; }0빈 문자열이 아닌 숫자 값으로 해석되도록 변수를 초기화합니다 "".
  • /^reference:/ { ref[i++] = $0; }reference:( ^줄 시작의 기준점) 으로 시작하는 각 줄 에 대해 전체 줄을 $0배열 요소에 복사 ref[i]하고 인덱스를 증가시킵니다.i++
  • /^sid:/ { ... }sid:다음으로 시작하는 모든 줄에 대해
  • for(j=0; j<i; j++) { ... }사용된 마지막 배열 요소를 가리킨 후 iindex 를 사용하여 작성된 모든 배열 요소를 반복합니다 j.
  • print ref[j];배열 요소의 내용, 즉 저장된 reference:행을 인쇄합니다.
  • print;현재 줄을 인쇄합니다. 즉, sid:
  • i=0;reference:배열 인덱스를 다음 행 집합의 시작 부분으로 재설정합니다.

스크립트는 다음 가정을 기반으로 합니다.

  • 입력은 일련의 블록으로 구성되며, 각 블록에는 다음이 포함됩니다.
    • 하나 이상의 줄로 구성된 reference:시퀀스
    • sid:하나의 선
  • 마지막 줄은 sid:한 줄이어야 합니다.
  • 일치하지 않는 행은 무시됩니다.

원래 질문의 경우 변환 방향이 잘못된 것으로 가정했습니다. 두 번째 스크립트는 반대 방향으로 변환합니다.

awk 'BEGIN { oldsid=""; ref=""; }
/^reference:/ { ref=$0; }
/^sid:/ { if(oldsid != $0) { if(oldsid != "") print oldsid; } if(ref!="")print ref; oldsid=$0; }
END { if (oldsid != "") print oldsid; }' inputfile > outputfile

설명하다:

  • BEGIN { oldsid=""; ref=""; }변수 초기화는 명확성을 위한 것이며 꼭 필요한 것은 아닙니다.
  • /^reference:/ { ref=$0; }reference:save the line to Variable 로 $0시작하는 각 줄 에 대해 ref아직 인쇄하지 마세요.
  • /^sid:/ { ... }sid:다음으로 시작하는 모든 줄에 대해
  • if(oldsid != $0) { if(oldsid != "") print oldsid; }이제 행이 변경된 경우 저장된 마지막 행이 sid:새 행에 속하므로 아직 인쇄하지 않습니다. 비어 있지 않으면 이전 줄 블록이 완료되었으므로 지금 인쇄할 수 있습니다. 첫 번째 항목을 찾으면 비어 있을 것입니다.reference:refsid:oldsidreference:sid:oldsidsid:
  • if(ref!="")print ref;저장한 파일이 있으면 reference:지금 인쇄해 주세요. (우리는 해당 라인으로 이전 블록을 닫았거나 sid:이제 현재 블록이 이전 블록과 reference:동일 하다는 것을 알고 있습니다.) 빈 문자열을 확인하는 것은 실제로 필요하지 않습니다. 왜냐하면 각 라인이 다음과 같다고 sid:가정하기 때문입니다. sid:앞에 줄이 있습니다 reference:.
  • oldsid=$0;sid:다음 행을 가져올 때 비교할 수 있도록 현재 행을 저장합니다 . 현재 행은 아직 인쇄되지 않았습니다.
  • END { if (oldsid != "") print oldsid; }마지막으로 마지막으로 저장된 sid:줄(있는 경우)을 인쇄합니다. (입력 파일이 비어 있으면 여기에 빈 줄이 인쇄되지 않습니다.)

스크립트는 다음 가정을 기반으로 합니다.

  • 모든 것 reference:뒤에는 하나가 온다sid:
  • 같은 행에 있는 모든 쌍 reference:과 합은 서로 이어집니다.sid:sid:

관련 정보