sed "하위 명령"에서 특수 문자를 이스케이프 처리하는 방법은 무엇입니까?

sed "하위 명령"에서 특수 문자를 이스케이프 처리하는 방법은 무엇입니까?

나는 xmllint --shell큰 XML 파일로 작업하고 있으며 이 write명령을 사용하여 테스트에 사용할 XML 조각을 작성하고 있습니다. 작성된 코드 조각에는 원본 XML 파일(선언, 네임스페이스 및 루트 노드)의 여러 줄이 필요합니다. 수동으로 행을 복사하지 않고도 이 행을 파일에 추가할 수 있기를 원합니다. 대신, 나는 이 매우 지루한 작업을 자동화하는 함수를 작성할 수 있도록 sed를 사용하여 줄을 추가하고 싶습니다. 이를 설명하기 위해 여기에 제가 달성하려는 작업의 예가 있습니다.

소스 XML(source.xml):

<?xml version="1.0" encoding="UTF-8"?>
<foo:root xmlns:foo="TheFooNameSpaceIsImportant">
    <foo:Entry>
        <foo:SomeNode>Foo1</foo:SomeNode>
        <foo:AnotherNode>Bar1</foo:AnotherNode>
    </foo:Entry>
    <foo:Entry>
        <foo:SomeNode>Foo2</foo:SomeNode>
        <foo:AnotherNode>Bar2</foo:AnotherNode>
    </foo:Entry>
    <foo:Entry>
        <foo:SomeNode>Foo3</foo:SomeNode>
        <foo:AnotherNode>Bar3</foo:AnotherNode>
    </foo:Entry>
    <!-- tens of thousands of others -->
    <foo:Entry>
        <foo:SomeNode>Foo20432</foo:SomeNode>
        <foo:AnotherNode>Bar20432</foo:AnotherNode>
    </foo:Entry>

</foo:root>

저장된 XML 조각(sample.xml):

<foo:Entry>
    <foo:SomeNode>Foo</foo:SomeNode>
    <foo:AnotherNode>Bar</foo:AnotherNode>
</foo:Entry>

따라서 source.xml의 맨 위 두 줄과 맨 아래 줄로 래핑해야 합니다. 그러나 역할로 인해 다음은 실패합니다 <.

$ sed -i 1i"`head -n 2 source.xml`" sample.xml
sed: -e expression #1, char 43: unknown command: `<'

이와 같은 하위 명령에서 제공되는 경우 이 문자를 이스케이프 처리할 수 있는 방법이 있습니까?

답변1

sed위에 제공된 명령에 대한 \BSD 출력에 설명된 대로 "i" 명령 뒤에는 텍스트가 와야 합니다.sed

그러나 그것은 단지 기대한다하나텍스트 줄. 더 많은 콘텐츠를 삽입하려면 첫 번째 줄 끝에 백슬래시를 추가해야 합니다.

sed "1i\\
$(head -n 2 source.xml | sed 's/$/\\/')
" sample.xml

이 (중첩 sed호출)은 약간 우스꽝스럽습니다. 내가 쓴대로다른 곳에서, 내부 스크립트 파일 편집을 위해 선택하는 도구는 가 아니지만 다음 sed과 같습니다 ex.

ex -sc '1,2ya | n! | 0pu | x' source.xml sample.xml

-s플래그는 ex일괄 처리를 위해 자동 모드에서 시작됩니다. -c실행할 명령을 지정합니다.

1,2ya첫 번째 파일의 처음 두 줄을 복사(즉, 복사)합니다 source.xml.

|명령 구분 기호입니다.

n!현재 파일의 변경 사항을 취소하고 다음 파일로 이동합니다. (이 경우에는 아무 것도 하지 않으므로 n괜찮습니다.)

0pu이전에 복사한 행을 "배치"(즉, 붙여넣기)하여 "0" 행 뒤에 배치합니다(즉, 첫 번째 행 위에 붙여넣기).

x종료하고 현재 파일의 변경 사항을 저장합니다.

지정되지 않은( 비어 있어도 백업 파일 확장자를 지정해야 하는 sed -iBSD에서는 작동하지 않음 ) POSIX의 명령과 달리 위 명령은 정확히 다음 과 같습니다.sed-iexPOSIX 호환.

답변2

sed여러 줄을 삽입/추가하는 경우 언제 삽입/추가를 중지해야 하는지 알 수 있도록 줄 끝을 이스케이프 처리해야 합니다 . 귀하의 경우에는 실행할 수 있습니다

head -n 2 source.xml | sed '1i\
1i\\
s/\\/&&/g
$!s/$/\\/' | sed -f - sample.xml

첫 번째 명령은 sed입력을 처리하고( 1i\이 두 줄 앞에 명령을 추가하고 마지막 줄이 아닌 경우 줄 끝과 백슬래시를 이스케이프 처리함) sed두 번째 명령에 스크립트로 전달합니다. , -i두 번째에 추가하십시오.sed

답변3

sed와 함께 사용 하지 마십시오 XML. XML은 정규 표현식이 제대로 지원하지 않는 상황별 데이터 구조입니다.https://stackoverflow.com/questions/1732348/regex-match-open-tags-book-xhtml-self-contained-tags

파서를 사용하십시오. 좋은 perl결과 XML::Twig:

#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
use XML::Twig;

my $xml_to_insert = XML::Twig -> parse ( '<foo:Entry>
    <foo:SomeNode>Foo</foo:SomeNode>
    <foo:AnotherNode>Bar</foo:AnotherNode>
</foo:Entry>') -> root -> copy;

my $xml = XML::Twig -> parse ( \*DATA ); 

$xml_to_insert -> paste ( 'first_child', $xml -> root );
$xml -> set_pretty_print ( 'indented_a');
$xml -> print;


__DATA__
<?xml version="1.0" encoding="UTF-8"?>
<foo:root xmlns:foo="TheFooNameSpaceIsImportant">
    <foo:Entry>
        <foo:SomeNode>Foo1</foo:SomeNode>
        <foo:AnotherNode>Bar1</foo:AnotherNode>
    </foo:Entry>
    <foo:Entry>
        <foo:SomeNode>Foo2</foo:SomeNode>
        <foo:AnotherNode>Bar2</foo:AnotherNode>
    </foo:Entry>
    <foo:Entry>
        <foo:SomeNode>Foo3</foo:SomeNode>
        <foo:AnotherNode>Bar3</foo:AnotherNode>
    </foo:Entry>
    <!-- tens of thousands of others -->
    <foo:Entry>
        <foo:SomeNode>Foo20432</foo:SomeNode>
        <foo:AnotherNode>Bar20432</foo:AnotherNode>
    </foo:Entry>

</foo:root>

산출:

<?xml version="1.0" encoding="UTF-8"?>
<foo:root xmlns:foo="TheFooNameSpaceIsImportant">
  <foo:Entry>
    <foo:SomeNode>Foo</foo:SomeNode>
    <foo:AnotherNode>Bar</foo:AnotherNode>
  </foo:Entry>
  <foo:Entry>
    <foo:SomeNode>Foo1</foo:SomeNode>
    <foo:AnotherNode>Bar1</foo:AnotherNode>
  </foo:Entry>
  <foo:Entry>
    <foo:SomeNode>Foo2</foo:SomeNode>
    <foo:AnotherNode>Bar2</foo:AnotherNode>
  </foo:Entry>
  <foo:Entry>
    <foo:SomeNode>Foo3</foo:SomeNode>
    <foo:AnotherNode>Bar3</foo:AnotherNode>
  </foo:Entry>
  <!-- tens of thousands of others -->
  <foo:Entry>
    <foo:SomeNode>Foo20432</foo:SomeNode>
    <foo:AnotherNode>Bar20432</foo:AnotherNode>
  </foo:Entry>
</foo:root>

이것은 설명을 위해 더 길고 더 자세하게 설명되어 있지만 본질적으로 코드 조각을 가져와서 구조에 복사하여 붙여넣는 것입니다. 좋고 쉽습니다.

XML::Twig와 동일한 작업을 수행할 수 있는 "parsefile_inplace"도 지원됩니다 sed -i. 따라서 예제는 다음과 같습니다.

my $xml_to_insert = XML::Twig -> parsefile ( 'source.xml' ) -> root -> copy;

XML::Twig -> new ( pretty_print => 'indented_a',
                   twig_handlers => { 
                       'foo:root' => sub {  
                            $xml_to_insert -> paste ( 'first_child', $_ ) 
                        } }) -> parsefile_inplace ('sample.xml'); 

또는 이것이 너무 복잡해 보인다면:

sub insert_source {
    my ( $twig, $branch ) = @_;  
    my $xml_to_insert = XML::Twig -> parsefile ( 'source.xml' ) -> root -> copy; 
    $xml_to_insert -> paste ( 'first_child', $branch ); 
}

my $xml = XML::Twig -> new ( twig_handlers => { 'foo:root' => \&insert_source } );
   $xml -> parsefile_inplace ( 'sample.xml'); 

관련 정보