XML 파일 process.xml이 있고 여기에 tmp.xml의 내용을 삽입하고 싶습니다. 하지만 주의할 점은 일치하는 두 패턴 사이에 이를 삽입해야 한다는 것입니다. 다음은 process.xml 파일의 일부입니다.
$cat process.xml
...
<fork name="data">
<path start="process_x" />
<path start="process_y" />
<path start="process_z" />
</fork>
...
...
<action name="process_x" />
....
....
</action>
<action name="process_z" />
....
....
</action>
tmp.xml 파일의 내용입니다.
$ cat tmp.xml
<path start="process_a" />
<path start="process_b" />
내 일치 패턴은 " process_z
" 및 " </fork>
"이며 내용은 이 패턴 사이에 붙여넣어야 합니다. 내가 시도한 것은 다음과 같습니다.
string=$(tac process.xml | grep -m1 -oP '(?<=path start="process_).*(?=" />)')
search="process_$string"
sed -e "/$search/ r tmp.xml" "process.xml"
그러나 내용은 및 에 삽입됩니다 tmp.xml
. 하지만 난 그냥 이렇게 안에 있어야 해요.fork
action
fork
...
<fork name="data">
<path start="process_x" />
<path start="process_y" />
<path start="process_z" />
<path start="process_a" />
<path start="process_b" />
</fork>
...
...
어떤 도움이라도 대단히 감사하겠습니다.
답변1
당신은 마지막으로 한 번 더 나타나기를 원하는 것 같습니다 <path start="process_
.
다음을 수행할 수 있습니다.
awk '
/path start="process_/ {print saved $0; saved=""; n++; next}
n {saved = saved $0 RS; next}
{print}
END{system("cat tmp.xml"); printf "%s", saved}' process.xml
path start="process_
그러나 이는 마지막 발생부터 끝까지 파일의 일부를 메모리에 저장하는 것을 의미합니다 .
또는 다음 명령을 사용하여 전체 파일을 메모리에 가져올 수 있습니다.
perl -0777 -pe 's/.*path start="process_.*?\n\K/<STDIN>/se
' process.xml < tmp.xml
</fork>
비어 있지 않은 다음 줄에서 변형을 확인하세요 .
perl -0777 -pe 's{.*path start="process_[^\n]*\n\K(?=\s*</fork>)}{<STDIN>}se
' process.xml < tmp.xml
들여쓰기를 정렬하고 누락된 경우 추가 줄바꿈을 추가하는 변형 tmp.xml
:
perl -0777 -pe 's{(?s:.*)(^\h*).*path start="process_.*\n\K(?=\s*</fork>)}{
$insert = <STDIN>;
$indent = $1;
$insert =~ s/^/$indent/gm;
$insert =~ s/\n?$/\n/;
$insert}me' process.xml < tmp.xml
를 사용 -0777 -pe 'code' file
하고 perl
실행한 code
다음 $_
해당 file
콘텐츠를 인쇄합니다 $_
(여기에서 수정됨 code
).
여기에는 바꾸기 명령이 있습니다 s{pattern}{replacement}flags
.
이러한 모든 명령에서 마지막으로 나타나는 패턴을 가져오는 비결은greedy로 이어지는 것입니다 .*
(여기서는 s
플래그 아래에 있으므로 개행 문자도 일치합니다). 욕심이 많기 때문에 ^
(플래그가 있는 줄의 시작 부분 m
), 일련의 가로 공백( ) 이 뒤따를 때까지 가능한 한 많은 문자를 일치시키려고 시도합니다. \h*
이를 캡처한 다음 패턴 $1
, (\h*)
그 다음 줄의 나머지( .*
이번에는 플래그가 없으므로 s
개행 문자를 먹지 않습니다) 다음에 개행 문자가 옵니다.
그런 다음 이것이 일치하는 텍스트의 시작임을 \K
알리기 위해 하나를 추가합니다 . perl
그런 다음 줄 바꿈 문자 뒤에 일련의 공백( \s*
) 및 가 오는지 확인하는 미리보기 연산자가 있습니다 </fork>
.
교체에서는 stdin에서 콘텐츠를 가져와 tmp.xml
각 줄의 시작 부분에 캡처된 들여쓰기를 삽입하고, 누락된 경우 후행 개행을 추가하고 이를 교체로 사용합니다.
또 다른 방법은 파일을 두 번 처리하는 것입니다. 패턴이 마지막으로 나타나는 줄 번호를 검색하기 위해 한 번, 파일을 삽입하기 위해 두 번째:
sed "$(awk '/path start="process_/{n=NR};END{print n}' < process.xml
)r tmp.xml" process.xml
아니면 다음과 같이 삽입할 수도 있습니다 </fork>
.
awk '/<\/fork>/{system("cat tmp.xml")};1' < process.xml
답변2
<fork>
파일이 하나만 있다고 가정하면 ...
</fork>
삽입된 문자열의 끝에 추가됩니다 .
</fork>
수정된 삽입 문자열로 바꿉니다 .
업데이트: 작업 태그에도 동일한 프로세스 이름이 포함되어 있으므로 전체 태그를 찾을 수 있도록 "검색" 문자열을 확장하세요 <path start="process_$string" />
. 또는 다음과 같이 "작업" 일치를 제거하기에 충분합니다. t="process_$string"