我有一个 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"
但它会将内容插入到andtmp.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
。
获取所有这些命令中最后一次出现的模式的技巧是前导贪婪.*
(这里位于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"