![파일에서 추출 및 재배열](https://linux55.com/image/146417/%ED%8C%8C%EC%9D%BC%EC%97%90%EC%84%9C%20%EC%B6%94%EC%B6%9C%20%EB%B0%8F%20%EC%9E%AC%EB%B0%B0%EC%97%B4.png)
일부 데이터를 추출하고 재정렬하려는 파일이 있습니다. 이전 파일에는 원본 데이터가 포함되어 있으며 이 파일은 입력입니다.
참조: 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++) { ... }
사용된 마지막 배열 요소를 가리킨 후i
index 를 사용하여 작성된 모든 배열 요소를 반복합니다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:
ref
sid:
oldsid
reference:
sid:
oldsid
sid:
if(ref!="")print ref;
저장한 파일이 있으면reference:
지금 인쇄해 주세요. (우리는 해당 라인으로 이전 블록을 닫았거나sid:
이제 현재 블록이 이전 블록과reference:
동일 하다는 것을 알고 있습니다.) 빈 문자열을 확인하는 것은 실제로 필요하지 않습니다. 왜냐하면 각 라인이 다음과 같다고sid:
가정하기 때문입니다.sid:
앞에 줄이 있습니다reference:
.oldsid=$0;
sid:
다음 행을 가져올 때 비교할 수 있도록 현재 행을 저장합니다 . 현재 행은 아직 인쇄되지 않았습니다.END { if (oldsid != "") print oldsid; }
마지막으로 마지막으로 저장된sid:
줄(있는 경우)을 인쇄합니다. (입력 파일이 비어 있으면 여기에 빈 줄이 인쇄되지 않습니다.)
스크립트는 다음 가정을 기반으로 합니다.
- 모든 것
reference:
뒤에는 하나가 온다sid:
- 같은 행에 있는 모든 쌍
reference:
과 합은 서로 이어집니다.sid:
sid: