줄 바꿈 문자가 포함 된 문자열 교체


10

bash쉘을 사용하면 다음과 같은 행이있는 파일에서

first "line"
<second>line and so on

나는 중 하나 개 이상 발생 대체하고자하는 "line"\n<second>과를 other characters각각의 시간을 가져 :

first other characters line and so on

둘 다 같은 특수 문자 문자열을 교체해야 그래서 "<및 개행 문자로.

다른 답변 사이에서 검색 한 후 sed명령의 오른쪽 ( other characters문자열) 에서 줄 바꿈을 수락 할 수 있지만 왼쪽 에는 줄 바꿈 을 사용할 수 없다는 것을 알았 습니다.

방법 (보다 간단 거기에 이 결과를 얻기 위해) sed또는 grep?


당신은 맥으로 일하고 있습니까? \n내가 물어 왜 만들 ewline 문이다. 사람들 s//\n/은 GNU로 할 수있는 대로 할 수 있는지 거의 묻지 sed않지만, 다른 대부분 sed은 오른쪽에서 탈출을 거부 할 것입니다. 여전히 \n이스케이프는 POSIX의 왼쪽에서 작동하며 항상 효과가 같지 않으므로 항상 유용 하지는 않지만 sed이식 가능하게 번역 할 수 있습니다 . y/c/\n/s/c/\n/g
mikeserv

답변:


3

세 가지 sed명령 :

sed '$!N;s/"[^"]*"\n<[^>]*>/other characters /;P;D'

sed -e :n -e '$!N;s/"[^"]*"\n<[^>]*>/other characters /;tn'

sed -e :n -e '$!N;/"$/{$!bn' -e '};s/"[^"]*"\n<[^>]*>/other characters /g'

세 가지 모두 기본 s///ubstitution 명령을 기반으로합니다 .

s/"[^"]*"\n<[^>]*>/other characters /

또한 sed에지 라인 의 출력이 서로 다른 경향이 있기 때문에 마지막 라인을 다룰 때주의를 기울입니다 . 이것은 의미가 마지막 $!!아닌 모든 행과 일치하는 주소 $입니다.

또한 모두 Next 명령을 사용하여 다음 입력 행을 추가하여 \newline 문자 다음의 패턴 공간에 추가합니다 . sed한동안 지낸 사람이라면 누구나 \newline 특성 에 의존하는 법을 배웠을 것입니다. 왜냐하면 그것을 얻는 유일한 방법은 그것을 명시 적으로 넣는 것뿐이기 때문입니다.

세 가지 모두 조치를 취하기 전에 가능한 한 적은 양의 입력을 읽으려고 시도합니다 sed. 그렇게하기 전에 전체 입력 파일에서 읽거나 읽을 필요가없는 한 빨리 작동합니다.

비록 그들이 모두했지만 N, 세 가지 모두 재귀 방법이 다릅니다.

첫 번째 명령

첫 번째 명령은 매우 간단한 N;P;D루프를 사용합니다. 이 세 명령은 모든 POSIX 호환에 내장되어 있으며 sed서로 훌륭하게 보완합니다.

  • N-이미 언급했듯이 N삽입 된 \newline 구분 기호 다음에 ext 입력 행을 패턴 공간에 추가합니다 .
  • P-같은 p; 그것은 P그러나 첫 번째 발생까지 -에 - 패턴 공간 rints \newline 문자. 따라서 다음과 같은 입력 / 명령이 주어집니다.

    • printf %s\\n one two | sed '$!N;P;d'
  • sed P단지 rints 하나 . 그러나 ...

  • D-같은 d; 이 D패턴 공간을 eletes 다른 라인 사이클을 시작한다. 달리 d , D단지까지 첫 번째 발생을 삭제 \n패턴 공간에서 ewline. \newline 문자 다음에 패턴 공간이 더 있으면 sed남은 줄로 다음 줄주기를 시작합니다. 경우 d앞의 예에서이 교환되었다 D, 예를 들어, sedP모두 RINT 하나 .

이 명령 은 ubstitution 문과 일치 하지 않는 행에 대해서만 반복됩니다 s///. 때문에 s///ubstitution가 제거 \n로 추가 ewline을 N때 나머지 결코 아무것도가 sed Deletes 패턴 공간을.

P및 / 또는 D선택적으로 적용하기 위해 테스트를 수행 할 수 있지만 해당 전략에 더 적합한 다른 명령이 있습니다. 대체 규칙의 일부 에만 일치하는 연속 행을 처리하기 위해 재귀가 구현되므로, ubstitution 의 양쪽 끝 과 일치하는 연속적인 행 시퀀스 s///가 제대로 작동하지 않습니다.

이 입력이 주어지면 :

first "line"
<second>"line"
<second>"line"
<second>line and so on

... 인쇄 ...

first other characters "line"
<second>other characters line and so on

그러나 처리합니다.

first "line"
second "line"
<second>line

... 괜찮아.

두 번째 명령

이 명령은 세 번째와 매우 유사합니다. 둘 다 :b목장 / test 레이블을 사용하고 ( 여기서 Joeseph R.의 답변에 설명되어 있음 ) 특정 조건에서 다시 되풀이 됩니다.

  • -e :n -e-이식 가능한 sed스크립트는 ewline 또는 새로운 인라인 xecution 문 으로 :레이블 정의를 구분합니다 . \n-e
    • :n-라는 레이블을 정의합니다 n. bn또는 을 사용하여 언제든지 되돌릴 수 있습니다 tn.
  • tn- t지정된 라벨로 추정 명령이 리턴 (없음이 제공되지 않은 경우 또는, 현재 행주기위한 스크립트를 종료) 이있는 경우 s///ubstitution 레이블 중 하나가 정의 된 이후 또는가 마지막으로 시작된 이후라는 t성공적인 ESTS을.

이 명령에서 일치하는 행에 대해 재귀가 발생합니다. 경우 sed성공적으로 패턴 대신 다른 문자 , sed받는 돌아 :n다시 레이블과 시도를. 경우 s///ubstitution이 수행되지 않습니다 sedautoprints에게 패턴 공간을 다음 행주기를 시작한다.

이것은 연속 시퀀스를 더 잘 처리하는 경향이 있습니다. 마지막 것이 실패하면 다음과 같이 인쇄됩니다.

first other characters other characters other characters line and so on

세 번째 명령

언급했듯이 여기의 논리는 마지막과 매우 유사하지만 테스트는 더 명확합니다.

  • /"$/bn-이건 sed테스트 야 때문에 b목장 명령이 주소의 함수이며, sed의지 만 b에 목장 다시 :n\newline이 추가 및 패턴 공간이 여전히으로 끝 "따옴표.

적게 사이에 다있다 N하고 b가능한 한 -이 방법으로 sed매우 빠르게 다음 줄이 규칙과 일치하지 수 있도록 필요한만큼 입력으로 정확하게 수집 할 수 있습니다. s///여기가 사용하는 것을 ubstitution의 다릅니다 g은 한 번에 모든 필요한 교체 할 수 있도록하고 - lobal 플래그. 동일한 입력이 주어지면이 명령은 마지막과 동일하게 출력됩니다.


사소한 질문에 대해 죄송하지만 DATA텍스트 입력 의 의미 와 방법은 무엇입니까?
BowPark

@BowPark-이 예제 <<\DATA\ntext input\nDATA\n에서는 구워졌지만 here 문서sed 에서 쉘이 전달한 텍스트 일뿐 입니다. 또는 처럼 작동 합니다. 도움이 되나요? sed 'script' filenameprocess that writes to stdout | sed 'script'
mikeserv

네, 감사합니다! D모든 수정 된 행이 없는 이유 는 두 배입니까? (필요에 따라 사용했습니다. 어쩌면 잘 모르겠습니다 sed)
BowPark

1
@BowPark 일 - 생략 때 두 배를 얻을 수 D있기 때문에 D, 그렇지 않으면 D당신은 지금 두 배로 무엇을보고 출력에서 eletes. 방금 수정을 마쳤으며 곧 확장 될 수 있습니다.
mikeserv

1
@BowPark-좋아, 나는 그것을 업데이트하고 옵션을 제공했다. 지금 읽고 이해하는 것이 조금 더 쉬울 것입니다. 나는 또한 그 D문제를 명시 적으로 다루었 다 .
mikeserv

7

글쎄, 나는 몇 가지 간단한 방법을 생각할 수 있지만 grep(어쨌든 대체를하지 않는) 또는 sed.

  1. 교체하려면 각각 의 발생 "line"\n<second>other characters사용을 :

    $ perl -00pe 's/"line"\n<second>/other characters /g' file
    first other characters line and so on
    

    또는 여러 개의 연속 된 발생을 "line"\n<second>하나로 처리하고 모든 단일 항목을 단일로 바꾸 other characters려면 다음을 사용하십시오.

    perl -00pe 's/(?:"line"\n<second>)+/other characters /g' file
    

    예:

    $ cat file
    first "line"
    <second>"line"
    <second>"line"
    <second>line and so on
    $ perl -00pe 's/(?:"line"\n<second>)+/other characters /g' file
    first other characters line and so on
    

    -00"선"에 의해 정의됨을 의미 '단락 모드 "에서 파일 읽기 펄 발생 \n\n않고 \n본질적으로, 각각 단락 선으로 처리된다. 따라서 대체는 개행에서 일치합니다.

  2. 어 wk

    $  awk -v RS="\n\n" -v ORS="" '{
          sub(/"line"\n<second>/,"other characters ", $0)
          print;
        }' file 
    first other characters line and so on
    

    동일한 기본 개념으로, 레코드 구분 기호 ( RS)를 설정하여 \n\n전체 파일을 슬러 핑 한 다음 출력 레코드 구분 기호를 아무 것도 설정하지 않은 경우 (다른 줄 바꿈이 인쇄 됨) sub()함수를 사용하여 교체합니다.


2
@mikeserv? 어느 것? 두 번째는 OP가 "하나 이상의 발생을 대체"하고 싶다고 말했기 때문에 단락을 먹는 것이 기대하는 것일 수 있습니다.
terdon

아주 좋은 지적입니다. 나는 더 집중 하고 매번 얻을 것이라고 생각하지만, 그것이 발생마다 하나의 교체인지 또는 발생 순서 당 하나의 교체가되어야하는지 확실하지 않다고 생각합니다 ... @BowPark?
mikeserv

발생 당 한 번의 교체가 필요합니다.
BowPark

@BowPark OK, 첫 번째 펄 접근 또는 awk가 모두 작동합니다. 그들은 당신에게 원하는 결과를 제공하지 않습니까?
terdon

그것은 작동하지만, 감사하지만 세 번째 줄은 awk이어야합니다 print;}' file. 나는 Perl을 피하고 바람직하게 sed는를 사용해야 합니다.
BowPark

6

전체 파일을 읽고 전체 대체를 수행하십시오.

sed -n 'H; ${x; s/"line"\n<second>/other characters /g; p}' <<END
first "line"
<second> line followed by "line"
<second> and last
END
first other characters  line followed by other characters  and last

예. 작동하지만 여러 번 발생하면 어떻게됩니까?
BowPark

응 수정
glenn jackman

1
nitpick을 다시 한 번 유감스럽게 생각하지만, ${cmds}GNU 고유 sed의 것입니다. 대부분의 다른 \n것들은 ewline이나 와 -e사이 에 구분 이 필요합니다 . 대괄호를 완전히 피하고 이식 가능하게 할 수 있으며 첫 줄에 다음과 같이 여분의 ewline 문자를 삽입하지 않아도됩니다 .p}\nsed 'H;1h;$!d;x;s/"line"\n<second>/other characters /g'
mikeserv

나는 그것을 테스트했는데 휴대용이 아닌 것 같습니다. 출력 시작 부분에 줄 바꿈이 추가로 표시되지만 GNU에서는 결과가 정확합니다.
BowPark

선행 줄 바꿈을 제거하려면 다음과 같이하십시오 sed -n '1{h;n};H; ${x; s/"line"\n<second>/other characters /g; p}'.
glenn jackman

3

다음 은 여러 번 연속적으로 발생하는 경우 작동하는 glenn의 답변 변형입니다 (GNU sed에서만 작동 ).

sed ':x /"line"/N;s/"line"\n<second>/other characters/;/"line"/bx' your_file

이는 :x분기를위한 레이블 일뿐입니다. 기본적으로 이것이하는 것은 대체 후 라인을 확인하고 여전히 일치 "line"하는 경우 :x레이블로 다시 분기 bx되어 버퍼에 다른 라인을 추가하고 처리를 시작한다는 것입니다.


@mikeserv 의미하는 바를 구체적으로 알려주십시오. 그것은 나를 위해 일했다.
Joseph R.

@ mikeserv 죄송합니다, 당신이 무슨 말을하는지 모르겠습니다. 위의 코드 줄을 다시 터미널에 복사했는데 제대로 작동했습니다.
Joseph R.

1
철회 됨-이것은 GNU에서 작동합니다. sedPOSIX가 아닌 레이블 처리는 레이블 선언의 구분 기호로 공백을 허용하기에 충분합니다. 그러나 다른 sed곳에서는 실패하고 실패 할 것입니다 N. GNU sedN마지막 행에서 종료하기 전에 패턴 공간을 인쇄하기 위해 POSIX 지침을 위반 하지만 POSIX는 N명령을 마지막 행에서 읽은 경우 아무 것도 인쇄 하지 않아야한다는 것을 분명히합니다 .
mikeserv

GNU를 지정하기 위해 게시물을 편집하면 투표를 취소하고 이러한 의견을 삭제합니다. 또한 GNU 버전 4 이상에서는 아무런 문제가 없지만 GNU v명령 에 대해 배울 가치가 있습니다 sed.
mikeserv

1
이 경우 나는 하나 더 제공 할 것입니다-이것은 다음과 같이 휴대 할 수 있습니다 sed -e :x -e '/"line"/{$!N' -e '};s/"line"\n<second>/other characters/;/"line"/bx'.
mikeserv
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.