sed를 사용하여 여러 줄 문자열을 바꾸려면 어떻게해야합니까? 를 \n사용하여

\n사용하여 대체 패턴을 추가 하면 패턴 sed이 일치하지 않습니다. 예:

$ cat > alpha.txt
This is
a test
Please do not
be alarmed

$ sed -i'.original' 's/a test\nPlease do not/not a test\nBe/' alpha.txt

$ diff alpha.txt{,.original}

$ # No differences printed out

이 기능을 작동 시키려면 어떻게해야합니까?



답변

간단한 전화에서 나오지도 , 그것을 가지고 하나 개 , 즉 패턴 공간, 텍스트의 라인을. \n입력에서 구분 된 한 줄의 텍스트 패턴 공간의 한 줄에는 없습니다 \n… 그래서 정규 표현식이 아무것도 찾지 못하는 이유입니다.

패턴 공간으로 여러 줄을 읽고 놀랍게도 잘 처리 할 수 ​​있지만 일반적인 노력보다 더 많은 노력이 필요합니다. Sed에는 이러한 유형의 작업을 허용하는 명령 세트가 있습니다. 여기 에 sed명령 요약 링크가 있습니다. . 내가 찾은 최고의 것인데, 나는 굴러 갔다.

그러나 sed의 마이크로 명령을 사용하기 시작하면 “한 줄짜리”아이디어를 잊어 버리십시오. 느낌이들 때까지 구조화 된 프로그램처럼 배치하는 것이 유용합니다 … 놀랍도록 간단하고 똑같이 특이합니다. 텍스트 편집의 “어셈블러 언어”로 생각할 수 있습니다.

요약 : sed를 간단한 것, 그리고 조금 더 사용하기 위해 사용하십시오. 그러나 일반적으로 한 줄로 작업 할 수 없을 때 대부분의 사람들은 다른 것을 선호합니다. 다른
누군가가 다른 것을 제안하게 할 것입니다. 최선의 선택이 무엇인지 확실하지 않습니다 (sed를 사용하지만 펄을 충분히 알지 못하기 때문입니다.)


sed '/^a test$/{
       $!{ N        # append the next line when not on the last line
         s/^a test\nPlease do not$/not a test\nBe/
                    # now test for a successful substitution, otherwise
                    #+  unpaired "a test" lines would be mis-handled
         t sub-yes  # branch_on_substitute (goto label :sub-yes)
         :sub-not   # a label (not essential; here to self document)
                    # if no substituion, print only the first line
         P          # pattern_first_line_print
         D          # pattern_ltrunc(line+nl)_top/cycle
         :sub-yes   # a label (the goto target of the 't' branch)
                    # fall through to final auto-pattern_print (2 lines)
       }
     }' alpha.txt

여기에는 동일한 스크립트가 있으며, 읽기 및 작업하기가 더 어려운 것으로 요약되어 있지만 일부는 확실하게 하나의 라이너를 호출 합니다.

sed '/^a test$/{$!{N;s/^a test\nPlease do not$/not a test\nBe/;ty;P;D;:y}}' alpha.txt

내 명령 “치트 시트”입니다

:  # label
=  # line_number
a  # append_text_to_stdout_after_flush
b  # branch_unconditional
c  # range_change
d  # pattern_delete_top/cycle
D  # pattern_ltrunc(line+nl)_top/cycle
g  # pattern=hold
G  # pattern+=nl+hold
h  # hold=pattern
H  # hold+=nl+pattern
i  # insert_text_to_stdout_now
l  # pattern_list
n  # pattern_flush=nextline_continue
N  # pattern+=nl+nextline
p  # pattern_print
P  # pattern_first_line_print
q  # flush_quit
r  # append_file_to_stdout_after_flush
s  # substitute
t  # branch_on_substitute
w  # append_pattern_to_file_now
x  # swap_pattern_and_hold
y  # transform_chars

답변

perl대신에 사용하십시오 sed:

$ perl -0777 -i.original -pe 's/a test\nPlease do not/not a test\nBe/igs' alpha.txt
$ diff alpha.txt{,.original}
2,3c2,3
< not a test
< Be
---
> a test
> Please do not

-pi -e표준 “제자리에서 교체”명령 줄 순서이며 -0777은 perl이 파일 전체를 제거합니다. 자세한 정보는 perldoc perlrun 을 참조하십시오 .


답변

\n기호를 다른 기호 로 바꾸고 평소대로 작동하는 것이 좋습니다 .

예 : 작동하지 않는 소스 코드 :

cat alpha.txt | sed -e 's/a test\nPlease do not/not a test\nBe/'

다음으로 변경할 수 있습니다.

cat alpha.txt | tr '\n' '\r' | sed -e 's/a test\rPlease do not/not a test\rBe/'  | tr '\r' '\n'

아무도 모른다면 \n유닉스 라인 엔딩, \r\n윈도우, \r클래식 맥 OS입니다. 일반적인 UNIX 텍스트는 \r기호를 사용하지 않으므로이 경우에 사용하는 것이 안전합니다.

이국적인 기호를 사용하여 \ n을 임시로 바꿀 수도 있습니다. 예를 들어-\ f (양식 피드 기호). 여기에서 더 많은 기호를 찾을 수 있습니다 .

cat alpha.txt | tr '\n' '\f' | sed -e 's/a test\fPlease do not/not a test\fBe/'  | tr '\f' '\n'

답변

모든 것을 고려하여, 전체 파일을 삼키고는 갈 수있는 가장 빠른 방법이 될 수 있습니다.

기본 구문은 다음과 같습니다.

sed -e '1h;2,$H;$!d;g' -e 's/__YOUR_REGEX_GOES_HERE__...'

파일이 엄청 나면 전체 파일을 고 블링하는 것이 옵션이 아닐 수 있습니다. 그러한 경우, 여기에 제공된 다른 답변은 작은 메모리 공간에서 작동하도록 보장되는 맞춤형 솔루션을 제공합니다.

다른 모든 핵 및 슬래시 상황의 경우, -e '1h;2,$H;$!d;g'원래 sed정규 표현식 인수 앞에 붙는 것만으로도 작업이 완료됩니다.

예 :

$ echo -e "Dog\nFox\nCat\nSnake\n" | sed -e '1h;2,$H;$!d;g' -re 's/([^\n]*)\n([^\n]*)\n/Quick \2\nLazy \1\n/g'
Quick Fox
Lazy Dog
Quick Snake
Lazy Cat

무엇을 -e '1h;2,$H;$!d;g'합니까?

1, 2,$, $!부품 라인이 직접 다음 명령이 실행 라인이 한도를 지정자입니다.

  • 1: 첫 줄만
  • 2,$: 두 번째부터 시작하는 모든 줄
  • $!: 마지막 이외의 모든 줄

확장되어 N 라인 입력의 각 라인에서 발생합니다.

  1: h, d
  2: H, d
  3: H, d
  .
  .
N-2: H, d
N-1: H, d
  N: H, g

g명령 라인에서 지정된 것이 아니라, 위의 d명령은 특별한 조항이있다 ” 시작 다음주기를. “이것은 방지 g마지막을 제외한 모든 라인에서 실행.

각 명령의 의미는 다음과 같습니다.

  • h다음 H각 광고 카피들로의 입력 라인을 상기 sed집의 보류 공간 . (임의의 텍스트 버퍼를 생각하십시오.)
  • 그런 d다음 각 행을 버려서 해당 행이 출력에 기록되지 않도록합니다. 그러나 홀드 공간 은 유지됩니다.
  • 마지막으로, 맨 마지막 줄에 g로부터 모든 라인의 축적 복원 보류 공간을 그 때문에 sed(오히려 라인 한번에 한 방식에 비해) 전체 입력에서의 정규 표현식을 실행할 수 있으며, 따라서 할 수있다 에 일치합니다 \n.

답변

sed: 세 가지 명령 멀티 라인 작업을 관리 할 수있다 N, D그리고 P(에 비교 정상 n , dp).

이 경우 패턴의 첫 번째 행을 일치시키고 N두 번째 행을 패턴 공간 에 추가 한 다음 s대체를 수행 하는 데 사용할 수 있습니다.

다음과 같은 것 :

/a test$/{
  N
  s/a test\nPlease do not/not a test\nBe/
}

답변

당신은 할 수 있지만 어렵습니다 . 다른 도구로 전환하는 것이 좋습니다. 바꾸려는 텍스트의 어떤 부분과도 일치하지 않는 정규식이 있다면 GNU awk에서 awk 레코드 구분 기호로 사용할 수 있습니다.

awk -v RS='a' '{gsub(/hello/, "world"); print}'

검색 문자열에 연속 된 줄 바꿈이 두 개 이상없는 경우 awk의 “단락 모드”(하나 이상의 빈 줄이 별도의 레코드)를 사용할 수 있습니다.

awk -v RS='' '{gsub(/hello/, "world"); print}'

쉬운 해결책은 Perl을 사용하고 파일을 메모리에 완전히로드하는 것입니다.

perl -0777 -pe 's/hello/world/g'

답변

나는 이것이 2 줄 일치에 대한 sed 솔루션이라고 생각합니다.

sed -n '$!N;s@a test\nPlease do not@not a test\nBe@;P;D' alpha.txt

3 줄 일치를 원하면 …

sed -n '1{$!N};$!N;s@aaa\nbbb\nccc@xxx\nyyy\nzzz@;P;D'

4 줄 일치를 원한다면 …

sed -n '1{$!N;$!N};$!N;s@ ... @ ... @;P;D'

“s”명령의 교체 부품이 줄을 줄이면 이와 같이 조금 더 복잡해집니다

# aaa\nbbb\nccc shrink to one line "xxx"

sed -n '1{$!N};$!N;/aaa\nbbb\nccc/{s@@xxx@;$!N;$!N};P;D'

repacement 부분이 선을 키우면 다음과 같이 조금 더 복잡해집니다

# aaa\nbbb\nccc grow to five lines vvv\nwww\nxxx\nyyy\nzzz

sed -n '1{$!N};$!N;/aaa\nbbb\nccc/{s@@vvv\nwww\nxxx\nyyy\nzzz@;P;s/.*\n//M;P;s/.*\n//M};P;D'