이 질문에 대한 답은 어디에서도 찾을 수 없습니다. 간단해 보이지만 아마도 그렇지 않을 수도 있다는 생각이 들기 시작했습니다.
sed가 이 문자열에서 STOP 전에 모든 CAT을 제거하도록 하고 싶습니다.
two CAT two four CAT CAT seven one STOP four CAT two CAT three
따라서 내가 원하는 결과는 다음과 같습니다.
two two four seven one STOP four CAT CAT two CAT three
문자열의 어느 위치에나 CAT가 있을 수 있습니다. 중지 표시는 어디에나 있을 수 있지만 다음 중 하나만 사용할 수 있으며 항상 STOP으로 표시됩니다.
(편집: 아래에 지적한 대로 제 질문은 불분명합니다. CAT에는 인접한 공백이 있어야 하나요, 아니면 경계로 어떤 문자라도 가질 수 있나요? 영숫자가 아닌 문자만 있을 수 있나요? 실제 사용 사례를 보여주기에는 꽤 힘들 것입니다. 큰 bash 기능) 너무 단순화했기 때문에 아래 솔루션은 인접성에 대해 다른 가정을 할 수 있다는 점을 독자에게 명심하십시오. 감사합니다)
답변1
CAT
이전 s가 더 이상 없을 때까지 루프에서 한 번에 하나씩 바꿀 수 있습니다 STOP
.
$ echo 'two CAT two four CAT CAT seven one STOP four CAT two CAT three' |
sed -e :a -e '/CAT.*STOP/s/CAT //;ta'
two two four seven one STOP four CAT two CAT three
답변2
어떤 이상한 경우 :
awk '{while($0~/CAT .*STOP/)sub(/CAT /,"")}1' file
$ echo 'two CAT two four CAT CAT seven one STOP four CAT two CAT three' |
awk '{while($0~/CAT .*STOP/)sub(/CAT /,"")}1'
two two four seven one STOP four CAT two CAT three
답변3
그리고perl
perl -pe 's/CAT (?=.*STOP)//g'
CAT
STOP
다음 줄이 존재하는 경우에만 교체됩니다.
답변4
(이것이 sed 퍼즐보다 더 중요하다면 sed를 사용하여 전혀 사용하지 않는 것이 좋습니다. 여기의 모호한 답변과 달리 Python에서는 이것을 쉽고 매우 명확하게 작성할 수 있습니다.)
아래와 같이 sed에서 루프를 사용할 수 있습니다. 코드 아래에 지침과 참고 사항이 있습니다.
s/STOP/@/
: loop
s/^\([^@]*\)CAT\(.*\)$/\1\2/
t loop
s/@/STOP/
p
다음과 같이 실행
$ sed -n -f t.sed
설명하는 대로 모든 줄을 수정합니다. 존재하지 않는 경우 입력 줄에서 모든 항목을 제거하도록 STOP
코드가 작성되었습니다 . CAT
또한 이 코드에서는 이것이 @
입력 줄에 나타나지 않을 것이라고 가정합니다. 그렇다면 다른 마커 문자를 찾아야 합니다.
무슨 일이죠? 코드를 살펴보겠습니다.
s/STOP/@/
존재하지 않는 항목과 일치하는 정규식을 작성하는 것은 어렵습니다 sed
. 단, 단일 문자의 경우(예 : 작업을 수행하는 x
경우)는 예외입니다. [^x]*
따라서 우리의 센티널을 STOP
줄의 나머지 부분에서 사용되지 않는 단일 문자로 바꾸십시오. 그러한 성격이 없으면 인생은 더욱 어려워지고 이것이 sed
실제로 작업에 적합한 도구가 아니라는 것을 기억합니다.
: loop
s/^\([^@]*\)CAT\(.*\)$/\1\2/
t loop
이것이 핵심 부분입니다. : loop
나중에 다시 분기할 수 있는 태그를 sed 스크립트에서 선언하세요. 다음으로 해당 줄에서 앞에 없는 태그를 s///
찾아 교체하고 앞과 뒤의 텍스트를 유지합니다. 대체가 발생하면 돌아가서 다시 시도합니다. 교체가 실패하면, 즉 교체가 발견되지 않으면 반환된 분기가 사용되지 않습니다.CAT
@
t loop
loop
CAT
loop
s/@/STOP/
p
실제 STOP
텍스트를 복원하고 마지막 줄을 인쇄합니다.