두 패턴 사이에 있는 각 레코드의 데이터 사이에서 줄바꿈을 어떻게 제거할 수 있나요?

두 패턴 사이에 있는 각 레코드의 데이터 사이에서 줄바꿈을 어떻게 제거할 수 있나요?

가급적이면 (bash에서)를 사용하여 구문 분석하고 다시 포맷해야 하는 큰 파일이 있습니다 sed. 파일에는 로 PATTERN_START시작하고 끝나는 반복 시퀀스가 ​​포함되어 있습니다 PATTERN_END. 이 시퀀스는 내가 변경하지 않고 유지해야 했던 다른 텍스트와 혼합되었습니다. 시퀀스에 여러 레코드가 있습니다(1부터 번호가 매겨짐).N, 어디N1~12까지 가능) 레코드는 다음 형식의 한 줄로 시작하는 줄 집합입니다.Record i1과 1 사이의 정수입니다.N, 다른 줄( ) 또는 한 줄로 끝납니다. 레코드 길이는 1줄에서 30줄까지 가능합니다.Record (i+1)PATTERN_END

다음은 입력 파일의 일반적인 표현입니다.

관련 없는 데이터          (줄이 많을 수도 있음)
모드_시작 |
기록 1 ⎤ |
데이터 1개 기록(최대 30줄)    |  (여러번 반복)
      ︙ ⎦ |  (최대 12개 레코드)    |
기록 2 |
2개의 데이터를 기록                        ⎦ |
패턴_END ⎦
관련 없는 데이터          (줄이 많을 수도 있음)

그래서 각 레코드의 모든 데이터 행을 PATTERN_START과 사이에 있는 레코드 에 대해서만 해당 행으로 집계 하고 싶습니다 .PATTERN_ENDRecord

누구든지 도와줄 수 있나요?

다음은 구문 분석해야 하는 파일의 예와 원하는 결과 유형입니다.

입력하다

Blabla
Blabla
PATTERN_OTHER
Record 1         <- record not between PATTERN_START and PATTERN_END tags => do not touch it
Data
Data
PATTERN_END
Blabla
PATTERN_START
Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line
Data
Data
Data
Record 2         <- record between PATTERN_START and PATTERN_END tags => to put in one line
Data
Data
Record 3         <- record between PATTERN_START and PATTERN_END tags => to put in one line
Data
Data
Data
Data
PATTERN_END
Blabla
Blabla
Blabla
Blabla
PATTERN_START
Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line
Data
Data
Data
PATTERN_END
Blabla
Blabla
PATTERN_OTHER
Record 1         <- record not between PATTERN_START and PATTERN_END tags => do not touch it
Data
Data
Record 2         <- record not between PATTERN_START and PATTERN_END tags => do not touch it
Data
PATTERN_END
Blabla
Blabla
PATTERN_START
Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line
Data
Record 2         <- record between PATTERN_START and PATTERN_END tags => to put in one line
Data
Data
Data
PATTERN_END
Blabla
Blabla

산출

Blabla
Blabla
PATTERN_OTHER
Record 1         <- was not between PATTERN_START and PATTERN_END tags => not modified
Data
Data
PATTERN_END
Blabla
PATTERN_START
Record 1 Data Data Data        <- record data grouped in one line
Record 2 Data Data             <- record data grouped in one line
Record 3 Data Data Data Data   <- record data grouped in one line
PATTERN_END
Blabla
Blabla
Blabla
Blabla
PATTERN_START
Record 1 Data Data Data        <- record data grouped in one line
PATTERN_END
Blabla
Blabla
PATTERN_OTHER
Record 1         <- was not between PATTERN_START and PATTERN_END tags => not modified
Data
Data
Record 2         <- was not between PATTERN_START and PATTERN_END tags => not modified
Data
PATTERN_END
Blabla
Blabla
PATTERN_START
Record 1 Data                  <- record data grouped in one line
Record 2 Data Data Data        <- record data grouped in one line
PATTERN_END
Blabla
Blabla

답변1

이것이 GNU sed로 원하는 것이라고 생각하십시오

 sed -n '/^PATTERN_START/,/^PATTERN_END/{
         //!{H;/^Record/!{x;s/\n\([^\n]*\)$/ \1/;x}};
         /^PATTERN_START/{h};/^PATTERN_END/{x;p;x;p};d
         };p' file

설명하다

sed -n #Non printing


'/^PATTERN_START/,/^PATTERN_END/{
#If the line falls between these two patterns execute the next block

  //!{
  #If the previous pattern matched from the line above is not on matched(so skip 
         the start and end lines), then execute next block

        H;
        #append the line to the hold buffer, so this appends all lines between 
       #`/^PATTERN_START/` and `/^PATTERN_END/` not including those.

        /^Record/!{
        #If the line does not begin with record then execute next block

            x;s/\n\([^\n]*\)$/ \1/;x
            #Swap current line with pattern buffer holding all our other lines 
            #up to now.Then remove the last newline. As this only executed when 
            #record is not matched it just removes the newline from the start 
            #of `data`.
            #The line is then put switched back into the hold buffer.

        }
        #End of not record block

    }; 
    #End of previous pattern match block

    /^PATTERN_START/{h};

    #If line begins with `PATTERN_START` then the hold buffer is overwritten 
    #with this line removing all the previous matched lines.

    /^PATTERN_END/{x;p;x;p}
    #If line begins with `PATTERN_END` the swap in our saved lines, print them,
    #then swap back in the PATTERN END line and print that as well.

    ;d
    #Delete all the lines within the range, as we print them explicitly in the 
    #Pattern end block above


         };p' file
         # Print everything that's not in the range print, and the name of the file

답변2

이것이 내가 생각해 낼 수 있는 최선의 방법입니다:

sed -n '/^PATTERN_START/, /^PATTERN_END/{
            /^PATTERN_START/{x;s/^.*$//;x};
            /^Record/{x;/^\n/{s/^\n//p;d};s/\n/ /gp};
            /^PATTERN_END/{x;/^\n/{s/^\n//p;d};s/\n/ /gp;g;p};
            /^Record/!H
        };   
        /^PATTERN_START/, /^PATTERN_END/!p'

설명하다

나는 당신이 의 홀드 공간(Hold Space)과 패턴 공간(Pattern Space)의 개념을 잘 알고 있다고 가정합니다 sed. 이 솔루션에서는 패턴 공간에서 많은 조작을 수행하게 됩니다. 따라서 첫 번째 요점은 -n자동 인쇄를 비활성화하고 필요한 경우 인쇄하는 옵션을 사용하는 것입니다.

첫 번째 작업은 선 사이의 모든 선을 연결하는 것입니다 Record.

다음 파일을 고려하십시오.

a
b
Record 1
c
d
Record 2
e
f
Record 3

선을 연결한 후 우리는 그것을 원합니다

a
b
Record 1 c d
Record 2 e f
Record 3

그래서 계획은 다음과 같습니다.

  1. 행을 읽고 이를 예약된 공간에 추가합니다.
  2. 줄이 로 시작하면 Record이전 레코드가 완료되고 새 레코드가 시작되었음을 의미합니다. 그래서 예약된 공간을 인쇄하고 새로 고치고 1번 지점부터 다시 시작합니다.

/^Record/!H포인트 1은 코드 (명령의 5행) 로 구현됩니다 . "줄이 로 시작하지 않으면 Record예약된 공간에 새 줄을 추가하고 예약된 공간에 이 줄을 추가합니다"라는 의미입니다.

포인트 2는 /^Record/{x;s/\n/ /gp;} 코드로 달성할 수 있습니다. 여기서 홀드 x공간과 패턴 공간이 교체되고, s명령은 \n모든 s를 s로 바꾸고 , p플래그는 패턴 공간을 인쇄합니다. 이를 사용하는 x또 다른 이점 은 이제 예약된 공간에 현재 Record행이 포함되어 지점 1과 2에서 또 다른 루프를 시작할 수 있다는 것입니다.

그러나 문제가 있습니다. 주어진 예에서 첫 번째 줄 앞에는 두 줄 ab 가 있습니다 Record. 우리는 이러한 영역을 \n대체하고 싶지 않습니다 . 로 시작하지 않으므로 Record포인트 1당 \n공간을 보존하기 위해 추가한 다음 해당 줄을 추가합니다. 따라서 예약된 공간의 첫 번째 문자가 이면 이전에 해당 문자가 발생하지 않았음을 \n의미하므로 이를 로 바꾸면 안 됩니다 . 이 작업은 명령을 통해 수행됩니다.Record\n

/^\n/{s/^\n//p;d}

따라서 전체 명령은 다음과 같습니다.

/^Record/{x;/^\n/{s/^\n//p;d};s/\n/ /gp};

Record이제 두 번째 문제는 행이 행으로 Record끝나는 것이 아니라 행으로 끝나는 경우에도 행을 연결하려고 한다는 것입니다 PATTERN_END. 선이 로 시작하더라도 점 2와 정확히 동일한 작업을 수행하고 싶습니다 PATTERN_END. 그래서 명령은 다음과 같습니다

/^PATTERN_END/{x;/^\n/?s/^\n//p;d};s/\n/ /gp}

그러나 문제가 있습니다. line 의 경우와 마찬가지로 Record이제 PATTERN_END해당 줄은 예약된 공간에서 끝납니다. 하지만 우리는 더 이상 전선 연결이 없을 것이라는 것을 알고 있습니다 PATTERN_END. 그래서 우리는 그것을 인쇄할 수 있습니다. 그래서 우리는 PATTERN_END라인을 패턴 공간으로 가져오고 g를 사용하여 인쇄합니다 p. 따라서 최종 명령은 다음과 같습니다.

/^PATTERN_END/{x;/^\n/?s/^\n//p;d};s/\n/ /gp;g;p}

다음 문제는 라인입니다 PATTERN_START. 위의 설명에서는 처음에는 예약된 공간이 비어 있다고 가정합니다. 그런데 잠시 후 PATTERN_END예약된 공간에 물건이 들어옵니다. (그것은 단지 PATTERN_END철사입니다). 를 사용하여 새 루프를 시작할 때 PATTERN_START예약된 공간을 지우고 싶습니다.

따라서 우리가 하는 일은 을 만났을 때 PATTERN_START홀드 공간과 패턴 공간의 내용을 교환하고 패턴 공간을 비운 다음 다시 교환하는 것입니다. 덕분에 공간을 깨끗하게 유지할 수 있습니다. 이것이 바로 다음 명령이 수행하는 작업입니다.

/^PATTERN_START/{x;s/^.*$//;x}

마지막으로 우리는 PATTERN_START행과 PATTERN_END행 사이에서 이 모든 작업을 수행하고 싶습니다. 다른 것들은 그냥 인쇄하면 됩니다. 이 작업은 명령을 통해 수행됩니다.

/^PATTERN_START/, /^PATTERN_END/{
    ----above commands go here----
};
/^PATTERN_START/, /^PATTERN_END/!p

이 모든 것을 종합하면 최종 명령이 제공됩니다. :)

답변3

다른 방법 sed:

sed '/PATTERN_START/,/PATTERN_END/{   # in this range
//!{                                  # if not start or end of range
/^Record/{                            # if line matches Record
x                                     # exchange pattern and hold space
/^$/d                                 # if pattern space is empty, delete it
s/\n/ /g                              # replace newlines with spaces
}
/^Record/!{                           # if line doesn't match Record
H                                     # append it to hold space
d                                     # then delete it
}
}
/PATTERN_END/{                        # at end of range
x                                     # exchange pattern and hold space
s/\n/ /g                              # replace newlines with space
G                                     # append hold space to pattern space
x                                     # exchange again
s/.*//                                # empty pattern space
x                                     # exchange again > empty line in hold space
}
}' infile

또는

sed '/PATTERN_START/,/PATTERN_END/{     # same as above
//!{                                    # same as above
: again
N                                       # pull the next line into pattern space
/\nRecord/!{                            # if pattern space doesn't match this
/\nPATTERN_END/!{                       # and doesn't match this either
s/\n/ /                                 # replace newline with space
b again                                 # go to : again
}
}
P                                       # print up to first newline
D                                       # then delete up to first newline
}
}' infile

한 줄:

sed '/PATTERN_START/,/PATTERN_END/{//!{/^Record/{x;/^$/d;s/\n/ /g};/^Record/!{H;d}};/PATTERN_END/{x;s/\n/ /g;G;x;s/.*//;x}}' infile

그리고

sed '/PATTERN_START/,/PATTERN_END/{//!{: again;N;/\nRecord/!{/\nPATTERN_END/!{s/\n/ /;b again}};P;D}}' infile

답변4

세 가지 버전을 만들었습니다.


v1


sed     -e'/^PATTERN_START/!b'  -e:n -eN  \
        -e'/\nPATTERN_END$/!bn' -eh\;s/// \
        -e'x;s/\n[[:print:]]*$//;x'       \
        -e's/\(\nRecord [[:print:]]*\)\{0,1\}\n/\1 /g'  \
        -e'G;P;D'       data

저거 출력되네모두편집된 파일만 적용Record사이에 나타나는 선PATTERN_{START,END}.


v2


sed   -ne'/\n/P;:n'    \
       -e'/^PATTERN_[OS]/!D'   -eN     \
       -e'/\nPATTERN_END$/!bn' -es///  \
       -e'/^PATTERN_S/s/\(\nRecord [[:print:]]*\)\{0,1\}\n/\1 /g'      \
       -eG\;D  ./data                 ###<gd data> haha

어느 것이 인쇄됩니까?Record내의 모든 줄PATTERN_{(START|OTHER),END}하지만 적용됩니다편집하다그 일이 일어난PATTERN_{START,END}.


v3


sed   -ne'/\n/P;:n'    \
       -e'/^PATTERN_START/!D'  -eN     \
       -e'/\nPATTERN_END$/!bn' -es///  \
       -e's/\(\nRecord [[:print:]]*\)\{0,1\}\n/\1 /g'      \
       -eG\;D  ./data

그리고 그거오직편집 및오직인쇄Record사이에 나타나는 선PATTERN_{START,END}.

다음은 입력 샘플을 실행한 후 각각에 대한 출력입니다. 출력 샘플은 가장 짧은 것부터 가장 긴 것까지 역순으로 표시됩니다.


v3


Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data Data
Record 2         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data
Record 3         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data Data Data
Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data Data
Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data
Record 2         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data Data

v2


Record 1         <- record not between PATTERN_START and PATTERN_END tags => do not touch it
Data
Data
Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data Data
Record 2         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data
Record 3         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data Data Data
Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data Data
Record 1         <- record not between PATTERN_START and PATTERN_END tags => do not touch it
Data
Data
Record 2         <- record not between PATTERN_START and PATTERN_END tags => do not touch it
Data
Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data
Record 2         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data Data

v1


Blabla
Blabla
PATTERN_OTHER
Record 1         <- record not between PATTERN_START and PATTERN_END tags => do not touch it
Data
Data
PATTERN_END
Blabla
PATTERN_START
Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data Data
Record 2         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data
Record 3         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data Data Data
PATTERN_START
Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line
Data
Data
Data
Record 2         <- record between PATTERN_START and PATTERN_END tags => to put in one line
Data
Data
Record 3         <- record between PATTERN_START and PATTERN_END tags => to put in one line
Data
Data
Data
Data
Blabla
Blabla
Blabla
Blabla
PATTERN_START
Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data Data
PATTERN_START
Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line
Data
Data
Data
Blabla
Blabla
PATTERN_OTHER
Record 1         <- record not between PATTERN_START and PATTERN_END tags => do not touch it
Data
Data
Record 2         <- record not between PATTERN_START and PATTERN_END tags => do not touch it
Data
PATTERN_END
Blabla
Blabla
PATTERN_START
Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data
Record 2         <- record between PATTERN_START and PATTERN_END tags => to put in one line Data Data Data
PATTERN_START
Record 1         <- record between PATTERN_START and PATTERN_END tags => to put in one line
Data
Record 2         <- record between PATTERN_START and PATTERN_END tags => to put in one line
Data
Data
Data
Blabla
Blabla

관련 정보