다음과 같은 줄이 포함된 파일이 있습니다.
ABCDABCBCBBBCBCDDBBBBBBBBBBBBBBBBBBBBBBBBBXYZ
ABCDCCCBCCBBBBBBBBBBBBBBBBBBBBBBXYZ
ABCDACDCDCCCCBBBBBBBBBBBBBBBBBBBBBBBBXYZ
그리고 나는 원한다
BBBBBBBBBBBBBBBBBBBBBXYZ
BBBBBBBBBBBBBBBBBBXYZ
BBBBBBBBBBBBBBBBBBBBXYZ
따라서 목표는 ABCD
연속된 4개의 s가 처음 나타나는 경우부터 시작하여 모든 항목을 삭제하는 것입니다 B
. 모든 줄은 로 시작하는 것이 보장되며 s 이전의 "관련" 체인이 끝나기 전에 줄에 ABCD
"떠나는" 일이 있어서는 안 됩니다 .BBBB
B
XYZ
나는 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*
지시할 수 있습니다.sed
BBBB
다른특징.
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 -e
sed
perl -n -e
print
sed -n
p
갈아 바수다(sed의 기본값) 또는 ERE( sed -E
). for 와 달리 다음 인수가 스크립트임을 나타내는 것은 선택 사항이 sed
아닙니다 .-e
perl
에서 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