파일에서 추출 및 재배열

파일에서 추출 및 재배열

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

참조: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 뒤에는 항상 참조가 옵니다.), 이와 같이 반복적인 블록이 있으므로 참조가 여러 개인 경우 새 파일 순서로 추가해야 합니다.

답변1

사용하시는 것 같으니후불 sid:s (multipe references:뒤에 단일 sids:=> references:및 쌍이 옴 sid:), 두 가지 솔루션.


해결 방법 1: 반전

다음 명령을 사용하면 됩니다 tac(이것은고양이역순으로) 입력과 출력을 반대로 하려면:tac input | awk | tac > output

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

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

해결 방법 2: 배열

reference:s가 오면 배열에 저장 한 다음 해당 항목을 만나면 다시 뱉어냅니다.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 $0to Variable 로 시작하는 모든 줄에 대해 ref아직 인쇄하지 마세요.
  • /^sid:/ { ... }sid:... 으로 시작하는 모든 줄에 대해
  • if(oldsid != $0) { if(oldsid != "") print oldsid; }sid:지금 줄이 변경된 경우 reference:저장된 마지막 줄은 ref새 줄에 속하므로 sid:아직 인쇄하지 않습니다. 비어 있지 않으면 동일한 줄 oldsid의 이전 블록이 완료되었으므로 이제 인쇄할 수 있습니다. 첫 번째 를 찾으면 비어 있을 것입니다 .reference: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:

관련 정보