나는 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 -i
BSD에서는 작동하지 않음 ) POSIX의 명령과 달리 위 명령은 정확히 다음 과 같습니다.sed
-i
ex
POSIX 호환.
답변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');