한 줄에서 두 개의 패턴을 찾아 패턴을 삭제하고 그 사이의 순서를 지정하세요.

한 줄에서 두 개의 패턴을 찾아 패턴을 삭제하고 그 사이의 순서를 지정하세요.

다음과 같은 줄이 포함된 파일이 있습니다.

ABCDABCBCBBBCBCDDBBBBBBBBBBBBBBBBBBBBBBBBBXYZ
ABCDCCCBCCBBBBBBBBBBBBBBBBBBBBBBXYZ
ABCDACDCDCCCCBBBBBBBBBBBBBBBBBBBBBBBBXYZ

그리고 나는 원한다

BBBBBBBBBBBBBBBBBBBBBXYZ
BBBBBBBBBBBBBBBBBBXYZ
BBBBBBBBBBBBBBBBBBBBXYZ

따라서 목표는 ABCD연속된 4개의 s가 처음 나타나는 경우부터 시작하여 모든 항목을 삭제하는 것입니다 B. 모든 줄은 로 시작하는 것이 보장되며 s 이전의 "관련" 체인이 끝나기 전에 줄에 ABCD"떠나는" 일이 있어서는 안 됩니다 .BBBBBXYZ

나는 sed이것에 가까운 변형을 시도했습니다.

sed 's/ABCD.*BBBB//g' filename 

XYZ마지막 패턴까지는 멈추지 않기 때문에 주는 것 같은데 BBBB, 첫 번째 패턴 이후에는 멈추기를 원합니다.

어떤 도움이라도 대단히 감사하겠습니다! !

답변1

sed당신이 의심하는 것처럼 당신의 방법이 실패하는 이유는 그것이 sed정규식을 기반으로 하고 이것이 "탐욕적"이기 때문입니다. 즉, 설명할 수 있는 가능한 가장 긴 문자열을 일치시키려고 시도합니다.

그래서 이것이 과제일 수도 있습니다 awk. 다음 프로그램을 고려해보세요:

awk '{n=index($0,"BBBB"); print substr($0,n+4)}' input.txt

BBBB$0그러면 현재 줄에서 하위 문자열( 로 표시됨)이 처음 나타나는 위치를 찾아 해당 위치를 에 저장합니다 n. 그런 다음 해당 위치에서 시작하여 B줄 끝까지 4(처음 4초를 제거하기 위해)를 더한 줄 부분을 인쇄합니다 .

ABCD예제 입력에서 알 수 있듯이 여기에는 시작 모드에 대한 언급이 없습니다.모두줄은 로 시작합니다 ABCD. 이 경우 줄의 시작 부분부터 (첫 번째 4-- 포함) 패턴까지 모든 내용을 삭제하면 충분합니다 B. 가정이 잘못된 경우, 특히 BBBB이전에 발생할 수 있는 경우 ABCD예상대로 작동하지 않습니다.

답변2

당신이 해야 할 일을 하세요묻다awk가 있는 ( remove everything starting with the ABCD up to, and including, the first occurence of 4 consecutive Bs.)의 경우 다음과 같습니다.

$ awk -v beg='ABCD' -v end='BBBB' '
    { gsub(end,"\n") }
    match($0,beg"[^\n]+\n") { $0=substr($0,1,RSTART-1) substr($0,RSTART+RLENGTH) }
    { gsub(/\n/,end) }
1' file
BBBBBBBBBBBBBBBBBBBBBXYZ
BBBBBBBBBBBBBBBBBBXYZ
BBBBBBBBBBBBBBBBBBBBXYZ

이는 ABCD가 줄의 첫 번째인지 또는 BBBB가 그 앞에 나타날 수 있는지에 관계없이 작동합니다.

$ echo 'xyz BBBB foo ABCD bar BBBB etc BBBB anon' |
    awk -v beg='ABCD' -v end='BBBB' '{gsub(end,"\n")} match($0,beg"[^\n]+\n"){$0=substr($0,1,RSTART-1) substr($0,RSTART+RLENGTH)} {gsub(/\n/,end)} 1'
xyz BBBB foo  etc BBBB anon

답변3

시퀀스가 한 번만 발생하는 경우 첫 번째 이전 시퀀스 만 삭제하도록 BBBB*지시할 수 있습니다.sedBBBB다른특징.

sed 's/^ABCD.*[^B]BBBB//'

BBBB시퀀스가 한 줄에 한 번만 시작 된다면 작업을 수행해야 합니다.

다음 문자열에서는 작동하지 않습니다.

에이 비 씨 디이BBBB에프BBBBXYZ

이는 두 번 발생하는 상황이고 BBBB앞에 B가 아닌 것이 있으므로 그리디 알고리즘은 두 번째에도 캡처하게 됩니다.

답변4

문제는 sed정규 표현식이 "탐욕적"이라는 것입니다(즉, 가능한 한 많은 항목을 일치시키려고 함). sed일치에 대한 탐욕스럽지 않은 수량자는 없지만 일치하려는 항목 뒤에 perl추가하면 됩니다 . ?예를 들어

$ sed 's/ABCD.*BBBB//g' input.txt 
XYZ
XYZ
XYZ
$ perl -p -e 's/ABCD.*?BBBB//g' input.txt 
BBBBBBBBBBBBBBBBBBBBBXYZ
BBBBBBBBBBBBBBBBBBXYZ
BBBBBBBBBBBBBBBBBBBBXYZ

그런데, 귀하와 같은 대부분의 간단한 스크립트는 대신 (또는 적절한 경우 명령이 아닌 명령문을 사용하여) 실행할 수 있지만 sed대신 perl regex를 사용합니다.perl -p -esedperl -n -eprintsed -np갈아 바수다(sed의 기본값) 또는 ERE( sed -E). for 와 달리 다음 인수가 스크립트임을 나타내는 것은 선택 사항이 sed아닙니다 .-eperl

에서 man perlre:

기본적으로 양자화된 하위 패턴은 "탐욕적"입니다. 즉, 패턴의 나머지 부분도 일치하도록 허용하면서 가능한 한 많이 일치합니다(특정 시작 위치 지정). 가능한 한 적은 횟수로 일치시키려면 수량자 뒤에 추가하세요 ?. 의미는 변경되지 않았으며 단지 "탐욕스러운"이라는 점에 유의하십시오.

*?        Match 0 or more times, not greedily
+?        Match 1 or more times, not greedily
??        Match 0 or 1 time, not greedily
{n}?      Match exactly n times, not greedily (redundant)
{n,}?     Match at least n times, not greedily
{n,m}?    Match at least n but not more than m times, not greedily

관련 정보