패턴 매칭 후 연속된 여러 줄의 위치 바꾸기

패턴 매칭 후 연속된 여러 줄의 위치 바꾸기

대용량 텍스트 파일을 편집하려고 합니다. 내가 달성하고 싶은 것은 행을 3에서 14 사이의 위치에서 16에서 27 사이의 위치로 바꾸는 것입니다. MySQL bin-log에서 UPDATE 문을 추출하여 파일에 넣었습니다. 문제는 bin-log에서 WHERE 절과 SET 절이 반전되어 있다는 점입니다. WHERE 절 앞에 SET 절을 넣어야 합니다. 현재 WHERE 절이 SET 절 앞에 옵니다. UPDATE 문에는 27개의 행이 있으며 이러한 UPDATE 문은 수천 개 있습니다. 따라서 각 UPDATE 문에 있는 SET 절의 13개 라인(15행부터 27행까지의 SET 라인 포함)은 모두 위치 2와 14에 배치되어야 하며 그 반대의 경우도 마찬가지입니다.

이것이 가능한지 모르겠습니다. 아래 글을 보고 이해하려고 노력했지만 전혀 이해가 되지 않았습니다. 정규식, SED 또는 AWK를 전혀 이해하지 못합니다. 문자열이 포함된 텍스트 파일에서만 줄을 바꾸려면 sed 또는 ed를 사용하시겠습니까?

다음은 샘플 출력과 필수 출력입니다. 업데이트 문 예

### UPDATE `db`.`tb`
### WHERE
###   @1=39741631
###   @2=49969113
###   @3=1
###   @4=34
###   @5='{"CustomerName":"S","CustomerEmail":"[email protected]","CustomerMobile":"9","VersionId":"5","InSrc":"3","Eagerness":"-1"}'
###   @6=NULL
###   @7=0
###   @8='2021-11-09 19:11:49'
###   @9=NULL
###   @10=1
###   @11=29
###   @12=NULL
### SET
###   @1=39741631
###   @2=49969113
###   @3=1
###   @4=34
###   @5='{\n  "CustomerName": "S",\n  "CustomerEmail": "[email protected]",\n  "CustomerMobile": "9",\n  "VersionId": "5",\n  "InSrc": "39",\n  "Eagerness": "-1"}'
###   @6='33195861'
###   @7=1
###   @8='2021-11-09 19:11:49'
###   @9='2021-11-09 19:11:50'
###   @10=1
###   @11=20
###   @12='Pushed to CVL panel'
--

원하는 출력

### UPDATE `db`.`tb`
### SET
###   @1=39741631
###   @2=49969113
###   @3=1
###   @4=34
###   @5='{\n  "CustomerName": "S",\n  "CustomerEmail": "[email protected]",\n  "CustomerMobile": "9",\n  "VersionId": "5",\n  "InSrc": "39",\n  "Eagerness": "-1"}'
###   @6='33195861'
###   @7=1
###   @8='2021-11-09 19:11:49'
###   @9='2021-11-09 19:11:50'
###   @10=1
###   @11=20
###   @12='Pushed to CVL panel'
### WHERE
###   @1=39741631
###   @2=49969113
###   @3=1
###   @4=34
### @5='{"CustomerName":"S","CustomerEmail":"[email protected]","CustomerMobile":"9","VersionId":"5","InSrc":"3","Eagerness":"-1"}'
###   @6=NULL
###   @7=0
###   @8='2021-11-09 19:11:49'
###   @9=NULL
###   @10=1
###   @11=29
###   @12=NULL
--

답변1

사용 sed:

#n

/^### WHERE/ {
        h
        :again
        n
        /^### SET/ !{
                H
                b again
        }
}

/^--$/ {
        H
        x
}

p

편집 sed스크립트는 먼저 라인 1을 사용하여 각 주기가 끝날 때 버퍼의 기본 출력을 끕니다 #n. 이렇게 하면 n명령이 아무 것도 출력하지 못하게 됩니다(버퍼에 새 줄을 읽는 데 사용합니다).

그런 다음 스크립트는 문자열이 포함된 줄을 찾을 때까지 읽은 각 줄을 인쇄합니다 ### WHERE. 문자열이 줄의 시작 부분에 있으면 "예약된 공간"(편집 스크립트의 루프 사이에서 내용이 수정되지 않는 보조 버퍼)에 해당 줄을 저장합니다. 그런 다음 ### SET줄 시작 부분에 문자열이 포함된 줄을 찾을 때까지 입력의 줄을 예약된 공간에 추가합니다 . 이는 명시적 루프(레이블 again및 조건 분기 명령)를 사용 b again하여 수행 됩니다.

그런 다음 스크립트 --x. 그런 다음 마지막에 인쇄합니다 p(나머지 코드의 직접적인 영향을 받지 않는 다른 모든 줄도 인쇄합니다).

다음과 같이 명령줄에서 실행할 수 있습니다.

sed -f script file

... script편집 스크립트가 포함된 파일은 어디에 있고 sed, file데이터가 포함된 파일은 어디에 있습니까?


sed나중에 사용하기 위해 저장해야 하는 행을 읽기 위해 명시적으로 반복하는 대신 단순히 범위 주소를 사용하고 해당 범위의 모든 행(마지막 행 제외)을 예약된 공간에 저장하는 더 짧은 스크립트입니다.

/^### WHERE/,/^### SET/ {
        /^### SET/ !H
        /^### WHERE/ h
        d
}

/^--$/ { H; x; }

난 아니다진짜이 문제를 해결하기 위해 를 사용하는 것이 좋지만 ed가능하며 질문에 다음을 표시했습니다., 그래서 우리는 다음을 시작합니다:

g/SET/ .,/--/-1 m ?WHERE?-1

이 단일 ed표현식은 m문자열을 포함하는 모든 행에 명령을 적용합니다 SET.

편집기 m의 명령ed행동다른 위치로 연결되는 하나 이상의 노선.

이동할 행은 명령 자체의 앞(왼쪽)에 지정되며 m이 행의 대상은 에 있습니다 m.

이 예에서는 SET현재 줄(포함된 줄)에서 문자열을 포함하는 줄 앞의 줄로 이동 합니다 --. 범위 행의 주소를 씁니다 .,/--/-1. .,/@12=/이동할 마지막 행에 항상 문자열이 포함되어 있거나 @12=항상 고정된 수의 행을 이동하려는 경우 .,+13에도 사용할 수 있습니다 .

단어가 포함된 최신 줄 위의 줄 WHERE이 해당 줄이 이동되는 위치입니다. 표현식은 ?WHERE?표현식과 일치하는 줄을 버퍼에서 뒤로 검색한 다음 -1일치하는 줄 앞의 줄을 선택합니다. -14항상 고정된 수의 행을 이동하는 경우 대상 주소로 사용할 수도 있습니다.

다음을 통해 명령줄에서 사용할 수 있습니다.

printf '%s\n' 'g/SET/ .,/--/-1 m ?WHERE?-1' ',p' 'Q' | ed -s file

이는 두 개의 명령 ,p(전체 버퍼 인쇄/출력)과 Q(무조건 종료)를 추가합니다. 이는 결과가 표준 출력으로 인쇄됨을 의미합니다.

,p및 를 Q단일 명령 wq또는 w및 로 변경 하면 q내부 편집이 수행됩니다.

항상 적절하게 백업된 데이터에 대해 이러한 테스트를 수행하십시오.

표현을 더 구체적으로 만들려면 다음을 사용하세요.

g/^### SET/ .,/^--$/-1 m ?^### WHERE?-1

이는 m문자열로 시작하는 모든 행에 명령을 적용하고 해당 문자열로 시작하는 최신 행 이전에 ### SET포함된 다음 행으로 행 범위를 이동합니다 .--### WHERE

이러한 유형의 편집을 수행할 때의 문제점은 ed편집자가 문서를 메모리로 읽어온다는 것입니다. 따라서 를 사용하는 것은 다른 스트림 편집 방법을 ed사용하는 것만큼 메모리 효율적이지 않으며 sed데이터가 너무 크면 사용하지 못할 수도 있습니다.

답변2

노력하다

gawk '
  BEGIN {RS = "--\n"; FS = "###[[:blank:]]+(WHERE|SET)\n"}
  {printf "%s### SET\n%s### WHERE\n%s%s", $1, $3, $2, RS}
' file

해당 위치에서 파일을 편집합니다(이 코드가 작동할 것이라고 확신하지 않는 한 이 작업을 수행하지 마십시오).

  1. 임시 파일 사용:
    f=$(mktemp)
    gawk '...' file > "$f" && mv "$f" file
    
  2. 그리고moreutils팩:
    gawk '...' file | sponge file
    
  3. GNU awk 사용
    gawk -i inplace '...' file
    

관련 정보