여러 줄에 걸쳐 SED 교체


11

이 세 줄을 찾으려고합니다.

<!--
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
-->

그것들을 다음으로 대체하십시오 :

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

내가 시도 할 때

sudo sed -i 's:<!-- <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> -->:<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />:' /myfile.xml

그것을 찾지 못하고 \ n도 넣으려고했지만 여전히 작동하지 않습니다.

sudo sed -i 's:<!--\n <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />\n -->:<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />:' /myfile.xml

이것들은 오류를 던지지 않으며 단지 주석 처리를 제거하지 않습니다. 어떤 조언이라도 감사 할 것입니다!

답변:


6

sed는 각 줄을 차례로 읽으므로 올바른 방향으로 움직이지 않으면 여러 줄 패턴과 일치하지 않습니다. 이 N명령은 입력에서 한 줄을 읽고이를 패턴 공간에 추가합니다.

sed -i -e '/^<!--$/ {
    N; /\n<Connector port="8009" protocol="AJP\/1\.3" redirectPort="8443" \/>$/ {
        N; /\n-->$/ {
            s/^<!--\n//; s/\n-->$//
        }
    }
}' /myfile.xml

아마도, 이외의 명령이 필요한 경우 ssed에서 awk 또는 perl로 전환해야합니다. 보다 일반적인 방식으로 여러 줄 주석에 대처하는 약간 더 유연한 Perl 스 니펫이 있습니다.

perl -i -pe '
    if (/<!--/) { $_ .= <> while !/-->/;
        s[<!--\n(<Connector port="8009" protocol="AJP/1\.3" redirectPort="8443" />)\n-->][$1];
    }' /myfile.xml

6

Sed는 라인 단위로 작동합니다. 여러 줄에서 작동하도록 만들 수는 있지만 그런 식으로 설계되지는 않았습니다. 내 의견으로는 그렇게 사용하려고 할 때 확실히 보여줍니다. 그러나 그렇게하기로 결정했다면 아마도 레지스터를 사용해야 할 것입니다. /programming/1251999/sed-how-can-i-replace-a-newline-n 에 대한 솔루션 중 일부를 확인 하여 수행 방법을 확인하십시오.

나는 이런 종류의 작업을 위해 sed 대신 perl을 사용하는 것을 선호합니다 (멀티 라인 지향, 나는 의미합니다). 검색 및 교체 ( BEGIN...) 전에 추가 해야하는 상용구 는 분명하지 않지만 정규 표현식이 더 깨끗해 보입니다.

perl -i.bak -pe 'BEGIN{undef $/;} s/<!--string-->/string/smg' file.xml

또는 그룹화를 사용하여 표현식을 줄이고 정규 표현식을 사용할 수 있습니다.

perl -i.bak -pe 'BEGIN{undef $/;} s/<!--(string_or_regex)-->/\1/smg' file.xml

주석 표시와 주석 처리를 해제 할 코드 사이에 줄 바꿈이 있거나없는 경우 모두에서 작동해야합니다.

적응 :

/programming/1030787/multiline-search-replace-with-perl


도와 주셔서 감사합니다. 고통스러워 보입니다. 해결 방법을 사용하기로 결정했습니다
Doug Molineux


1
  • /<\!--/ : 일치하는 문자열
  • :X : 분기 명령 "b"의 레이블입니다.
  • /-->/ : 일치하는 문자열
  • s@...@...@p : "<!-", "->"를 제거하고 인쇄 결과
  • d : 패턴 공간을 삭제하고 새주기를 시작합니다
  • N : /-> /와 일치하지 않으면 줄을 추가하십시오.
  • bX : 분기에서 : X 레이블로
  • p : / <!-/와 일치하지 않는 문자열을 인쇄하십시오.

sed -rn '
/<!--/ {
    :X
    /-->/ {
        s@<!--\s*(<.+/>)\s*-->@\1@p
        d
    }
    N
    bX
};p'

그리고이 두 번째 방법은 일반적인 작은 크기의 텍스트 파일 (쉘 스크립트 파일 필요)을 간단한 복사 및 붙여 넣기로 대체합니다.

#!/bin/bash

# copy & paste content that you want to substitute

AA=$( cat <<\EOF | sed -z -e 's#\([][^$*\.#]\)#\\\1#g' -e 's#\n#\\n#g'
<!--
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
-->
EOF
)

BB=$( cat <<\EOF | sed -z -e 's#\([&\#]\)#\\\1#g' -e 's#\n#\\n#g'
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
EOF
)

sed -z -i 's#'"${AA}"'#'"${BB}"'#g' *.xml   # apply to all *.xml files

1) 답변 주셔서 감사합니다. 2) 코드 스 니펫 만 삽입하는 것은 실제로 좋지 않습니다. 설명, 수행 방식 및 방법을 설명하면 훨씬 좋습니다.
peterh-복 직원 모니카
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.