다른 파일의 일치하는 두 줄 사이에 한 파일의 내용을 삽입하는 방법은 무엇입니까?

다른 파일의 일치하는 두 줄 사이에 한 파일의 내용을 삽입하는 방법은 무엇입니까?

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. 하지만 난 그냥 이렇게 안에 있어야 해요.forkactionfork

...
<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"

관련 정보