파일의 두 마커 사이에 있는 모든 내용을 어떻게 삭제합니까?

파일의 두 마커 사이에 있는 모든 내용을 어떻게 삭제합니까?

텍스트 파일에 다음과 같은 문자열 사이에 있는 모든 내용을 원하는 텍스트가 있습니다 \{{[}.{]}\} 하고 싶습니다. 이 두 개의 문자열~할 수 있다같은 줄에 있을 뿐만 아니라 다른 줄에도 누워 있습니다. 두 경우 모두, ~에시작 부분이 있는 줄에서 \{{[}앞의 텍스트, 즉 왼쪽의 텍스트가 삭제되는 것을 원하지 않습니다. 이후의 텍스트도 마찬가지입니다 {]}\}.

예는 다음과 같습니다. 콘텐츠가 포함된 텍스트 파일이 제공됩니다.

Bla Bla bla bla \{{[} more bla bla
even more bla bla bla bla. 

A lot of stuff might be here.

Bla bla {]}\} finally done.

Nonetheless, the \{{[} show {]}\} goes on.

스크립트는 콘텐츠가 포함된 다른 텍스트 파일을 반환해야 합니다.

Bla Bla bla bla  finally done.

Nonetheless, the  goes on.

불행하게도 이 단순해 보이는 작업은 제가 sed. 나는 행복하다어느표준 Linux 시스템(C 및 일부 Java가 이미 설치되어 있음)에 아무것도 설치할 필요가 없는 한 어떤 언어로든 솔루션을 사용할 수 있습니다.

답변1

와 함께 perl:

perl -0777 -pe 's/\Q\{{[}\E.*?\Q{]}\}\E//gs'

전체 입력은 처리되기 전에 메모리에 로드됩니다.

\Qsomething\Esomething정규식이 아닌 리터럴 문자열로 처리됩니다 .

일반 파일을 내부에서 수정하려면 다음 -i옵션을 추가하세요.

perl -0777 -i -pe 's/\Q\{{[}\E.*?\Q{]}\}\E//gs' file.txt

GNU awk또는 mawk:

awk -v 'RS=\\\\\\{\\{\\[}|\\{\\]}\\\\}' -v ORS= NR%2

거기서 우리는기록 구분 기호시작 또는 끝 마커 중 하나로 사용됩니다(여기서는 정규 표현식만 gawk지원 mawk합니다 RS). 그러나 정규 표현식 연산자(백슬래시, {, [)인 문자와 백슬래시는 -v( \n, ...와 같은 항목에 사용되는) 인수에 특별하기 때문에 다시 한 번 이스케이프 해야 합니다 \b. 따라서 수많은 백슬래시가 발생합니다.

그런 다음 우리가 해야 할 일은 다른 모든 레코드를 인쇄하는 것뿐입니다. 모든 홀수 레코드에 대해 (true) NR%2입니다 .1

두 솔루션 모두 마커가 일치하고 해당 섹션이 중첩되지 않은 것으로 가정합니다.

최신 버전의 GNU를 사용하여 파일을 내부에서 수정하려면 ¹ 옵션을 awk추가하세요 -i /usr/share/awk/inplace.awk.


¹사용하지 마세요-i inplaceas 는 누군가 악성 코드를 심었을 수 있는 현재 작업 디렉터리에서 확장명(as 또는 )을 먼저 gawk로드하려고 시도합니다 . 와 함께 제공되는 확장 프로그램 의 경로는 시스템에 따라 다를 수 있습니다.inplaceinplaceinplace.awkinplacegawkgawk 'BEGIN{print ENVIRON["AWKPATH"]}'

답변2

sed   -e:t -e'y/\n/ /;/\\{{\[}/!b'               \
      -e:N -e'/\\{{\[.*{\]}\\}/!N'               \
           -e's/\(\\{{\[}\).*\n/\1/;tN'          \
           -e'y/ /\n/;s/\\{{\[}/& /;ts'          \
      -e:s -e's/\(\[} [^ ]*\)\({\]}\\}\)/\1 \2/' \
      -ets -e's/..... [^ ]* .....//;s/ //g;bt'   \
<<""
#Bla Bla {]}\} bla bla \{{[} more bla bla
#even more bla bla bla bla. \{{[} 
#
#A lot of stuff might be here.
#hashes are for stupid syntax color only
#Bla bla {]}\} finally {]}\} done.
#
#Nonetheless, the \{{[} show {]}\} goes \{{[} show {]}\} on.

#Bla Bla {]}\} bla bla  finally {]}\} done.
#
#Nonetheless, the  goes  on.

하지만 훨씬 더 좋은 방법이 있습니다. 훨씬 적은 수의 대체가 이루어지며, 대체는 .*항상 수행되는 것이 아니라 한 번에 두 문자씩 수행됩니다 . 실제로 사용되는 유일한 시간은 .*처음 발생한 시작이 첫 번째 다음 끝과 확실히 쌍을 이룰 때 공간 사이의 패턴 공간을 지우는 것입니다. 나머지 시간은 모두 다음 발생 구분 기호에 도달하는 데 필요한 만큼만 삭제합니다 sed. D돈이 나한테 그걸 가르쳐줬어요.

sed -etD -e:t -e'/\\{{\[}/!b'  \
    -e's//\n /;h;D'       -e:D \
    -e'/^}/{H;x;s/\n.*\n.//;}' \
    -ett    -e's/{\]}\\}/\n}/' \
    -e'/\n/!{$!N;s//& /;}' -eD \
<<""
#Bla Bla {]}\} bla bla \{{[} more bla bla
#even more bla bla bla bla. \{{[} 
#
#A lot of stuff might be here.
#hashes are for stupid syntax color only
#Bla bla {]}\} finally {]}\} done.
#
#Nonetheless, the \{{[} show {]}\} goes \{{[} show {]}\} on.

#Bla Bla {]}\} bla bla  finally {]}\} done.
#
#Nonetheless, the  goes  on.

그러나 RHS \n줄 바꿈 이스케이프는 문자 그대로의 백슬래시 이스케이프 줄 바꿈으로 대체되어야 할 수도 있습니다.

보다 일반적인 버전은 다음과 같습니다.

#!/usr/bin/sed -f
####replace everything between START and END
   #branch to :Kil if a successful substitution
   #has already occurred. this can only happen
   #if pattern space has been Deleted earlier
    t Kil
   #set a Ret :label so we can come back here
   #when we've cleared a START -> END occurrence
   #and check for another if need be
    :Ret
   #if no START, don't
    /START/!b
   #sigh. there is one. get to work. replace it
   #with a newline followed by an S and save
   #a copy then Delete up to our S marker.
    s||\
S|
    h;D
   #set the :Kil label. we'll come back here from now
   #on until we've definitely got END at the head of
   #pattern space.
    :Kil
   #do we? 
    /^E/{
       #if so, we'll append it to our earlier save
       #and slice out everything between the two newlines
       #we've managed to insert at just the right points        
        H;x
        s|\nS.*\nE||
    }
   #if we did just clear START -> END we should
   #branch back to :Ret and look for another START
    t Ret
   #pattern space didnt start w/ END, but is there even
   #one at all? if so replace it w/ a newline followed
   #by an E so we'll recognize it at the next :Kil
    s|END|\
E|
   #if that last was successful we'll have a newline
   #but if not it means we need to get the next line
   #if the last line we've got unmatched pairs and are
   #currently in a delete cycle anyway, but maybe we
   #should print up to our START marker in that case?
    /\n/!{
       #i guess so. now that i'm thinking about it
       #we'll swap into hold space, and Print it
        ${  x;P;d
        }
       #get next input line and add S after the delimiting
       #newline because we're still in START state. Delete
       #will handle everything up to our marker before we
       #branch back to :Kil at the top of the script
        N
        s||&S|
    }
   #now Delete will slice everything from head of pattern space
   #to the first occurring newline and loop back to top of script.
   #because we've definitely made successful substitutions if we
   #have a newline at all we'll test true and branch to :Kil 
   #to go again until we've definitely got ^E
    D

...코멘트를하지 않고...

#!/usr/bin/sed -f
    t Kil
    :Ret
    /START/!b
    s||\
S|
    h;D
    :Kil
    /^E/{
        H;x
        s|\nS.*\nE||
    }
    t Ret
    s|END|\
E|
    /\n/!{
        ${  x;P;d
        }
        N
        s||&S|
    }
    D

댓글이 달린 버전을 클립보드에 복사하고 다음을 수행했습니다.

{ xsel; echo; } >se.sed
chmod +x se.sed
./se.sed <se.sed

#!/usr/bin/sed -f
####replace everything between
   #branch to :Kil if a successful substitution
   #has already occurred. this can only happen
   #if pattern space has been Deleted earlier
    t Kil
   #set a Ret :label so we can come back here
   #when we've cleared a  occurrence
   #and check for another if need be
    :Ret
   #if no  at the head of
   #pattern space.
    :Kil
   #do we?
    /^E/{
       #if so, we'll append it to our earlier save
       #and slice out everything between the two newlines
       #we've managed to insert at just the right points
        H;x
        s|\nS.*\nE||
    }
   #if we did just clear  we should
   #branch back to :Ret and look for another , but is there even
   #one at all? if so replace it w/ a newline followed
   #by an E so we'll recognize it at the next :Kil
    s|END|\
E|
   #if that last was successful we'll have a newline
   #but if not it means we need to get the next line
   #if the last line we've got unmatched pairs and are
   #currently in a delete cycle anyway, but maybe we
   #should print up to our

답변3

파일이 test.txt인 경우 다음을 사용할 수 있습니다.

sed ':a;N;$!ba;s/\n/ /g' test.txt|sed 's/\\{{\[}.*{\]}\\}//' 

첫 번째 sed는 모든 줄 바꿈을 제거하고 두 번째 sed는 태그 내부의 텍스트를 제거합니다.

좀 더 일반적인 해결책이 필요한지 모르겠습니다.

관련 정보