sed를 사용하여 특정 태그 사이의 하위 문자열 바꾸기

sed를 사용하여 특정 태그 사이의 하위 문자열 바꾸기

두 개의 sed 명령을 하나로 결합하고 싶지만 어떻게 해야 할지 잘 모르겠습니다. 여러 가지 방법을 시도했지만 성공하지 못했습니다.

결과적으로 특정 토큰 사이의 모든 슬래시를 백슬래시로 바꾸려고 합니다. 그 결과는 다음과 같습니다.

원천:

<FilePath>a/b/c/d</FilePath> 
<OtherTags>Bob</OtherTags>
<FilePath>1/2/3/4</FilePath>

결과:

<FilePath>a\b\c\d</FilePath>
<OtherTags>Bob</OtherTags>
<FilePath>1\2\3\4</FilePath>

레이블 사이의 텍스트를 변경하는 다음 명령을 찾았습니다.

sed -i -e 's/\(<FilePath>\).*\(<\/FilePath>\)/<FilePath>TEXT_TO_REPLACE_BY<\/FilePath>/g' test.txt

하지만 이 명령은 모든 텍스트를 대체합니다... 그래서 제가 원하는 것은 텍스트를 유지하고 다음 명령을 사용하여 슬래시를 백슬래시로 바꾸는 것입니다.

sed -e 's/\\/\//g' test.txt

하지만 이 둘을 결합하는 데 어려움을 겪습니다.

당신의 도움을 주셔서 감사합니다.

답변1

match()에 대한 세 번째 인수를 일치시키려면 GNU awk를 사용하십시오.

awk 'match($0,/(.*<FilePath>)(.*)(<\/FilePath>.*)/,a){ gsub("/","\\",a[2]); $0=a[1] a[2] a[3] } 1' file
<FilePath>a\b\c\d</FilePath>
<OtherTags>Bob/Smith</OtherTags>
<FilePath>1\2\3\4</FilePath>

위의 내용은 다음 입력으로 실행되었습니다.

$ cat file
<FilePath>a/b/c/d</FilePath>
<OtherTags>Bob/Smith</OtherTags>
<FilePath>1/2/3/4</FilePath>

답변2

주문하다

sed -e 's/\//\\/g' -e 's/<\\/<\//g' filename

산출

<FilePath>a\b\c\d</FilePath> 
<OtherTags>Bob</OtherTags>
<FilePath>1\2\3\4</FilePath>

답변3

확장된 정규식 패턴과 함께 GNU sed를 사용하면 태그가 인용문이나 주석의 일부가 아니라는 가정 하에 동일한 줄에서 열고 닫는 xml 태그인 FilePath를 단계별로 일치시킬 수 있습니다.

sed -Ee ' :a;s|<(FilePath)>([^/]*(/[^/]*)*)/([^/]*</\1>)|<\1>\2\\\4|;ta' file
perl -lpe '
 s{<FilePath>\K.*?(?=</FilePath>)}
  <$& =~ tr|/|\\|r>xge;
' file

태그의 시작과 끝 사이의 섹션을 분리하고 해당 섹션의 슬래시를 백슬래시로 변환합니다.

우리의 의도를 표현하기 위해 여러 줄의 정규식을 작성할 수 있습니다.

snr='
s|
  <(FilePath)>
   ( [^/]* ([/][^/]*)* )
          /
   ( [^/]* )
  </\1>
|<\1> \2 \\ \4 </\1>|
'
ws=$'\t \n'
sed -E ":a;${snr//[$ws]/};ta" file

답변4

이는 sed 및 tr을 사용하여 파이프를 통해 구축된 매우 간단한 솔루션입니다. 다음을 가정합니다.

  • 내부에는 중첩된 태그가 없습니다 (대체는 다음 이후 <FilePath>…</FilePath>에만 수행됩니다 ).<<FilePath>
  • <FilePath>리터럴 문자열(no <![CDATA[<FilePath>/blah]]>또는 <mytag label="<FilePath>">) 내에 나타나지 않습니다.
  • 마지막 줄에 종료 줄 바꿈이 없더라도 sed 구현은 이를 올바르게 처리합니다.

아이디어는 tr줄 바꿈 <과 개행을 사용하는 것입니다. 이 방법으로 sed가 "줄"을 처리할 때 실제로는 열기/닫기 태그와 텍스트 열기/닫기 태그 사이의 텍스트를 처리합니다.

tr '<\n' '\n<' | sed '/^FilePath>/ y:/:\\:' | tr '<\n' '\n<'

이것은 Perl 솔루션입니다. 다음을 가정합니다.

  • 내부에는 중첩된 태그가 없습니다 <FilePath>…</FilePath>.
  • <FilePath>리터럴 문자열(no <![CDATA[<FilePath>/blah]]>또는 <mytag label="<FilePath>">) 내에 나타나지 않습니다.
  • <FilePath>항상 </FilePath>같은 줄을 따라가세요).

구성은 매우 자연스럽습니다. 즉, backslashify내부 텍스트 에 기능을 적용합니다 <FilePath>…</FilePath>. 정규식 .*?은 비탐욕적 일치입니다. 같은 줄에 여러 블록이 있는 경우 욕심쟁이 일치는 .*해당 줄의 모든 것을 처음부터 <FilePath>마지막까지 대체합니다. 슬래시 바로 앞이나 뒤를 바꾸지 않고 중첩된 태그를 허용하는 고급 버전입니다.</FilePath><FilePath>…</FilePath>s:(?!<<)/(?!>):\\:tr:/:\\:><

perl -pe 'sub backslashify {local $_ = $_[0]; s:(?!<<)/(?!>):\\:; return $_} s:(<FilePath>)(.*?)(</FilePath>):$1.backslashify($2).$3:e'

관련 정보