我有一个文件Afile:
<start>
<memory>
<hdd>10</hdd>
<hdc>40</hdc>
</memory>
<storage>
<disk>
<disk1>firstname</disk1>
</disk>
<disk>
<disk1>secondname</disk1>
</disk>
<map>
<code>1</code>
</map>
<map>
<code>2</code>
</map>
</storage>
</start>
我有第二个文件Bfile:
<disk>
<disk1>thirdname</disk1>
</disk>
如何使用sed我可以将Bfile的内容插入到Afile中。所以最后我需要有以下文件:
<start>
<memory>
<hdd>10</hdd>
<hdc>40</hdc>
</memory>
<storage>
<disk>
<disk1>firstname</disk1>
</disk>
<disk>
<disk1>secondname</disk1>
</disk>
<disk>
<disk1>thirdname</disk1>
</disk>
<map>
<code>1</code>
</map>
<map>
<code>2</code>
</map>
</storage>
</start>
所以它应该在最后一个模式之后插入。当我使用以下命令时,我得到以下结果:
sed -e'/ disk&gt; / rBfile'Afile
<start>
<memory>
<hdd>10</hdd>
<hdc>40</hdc>
</memory>
<storage>
<disk>
<disk1>firstname</disk1>
</disk>
<disk>
<disk1>thirdname</disk1>
</disk>
<disk>
<disk1>secondname</disk1>
</disk>
<disk>
<disk1>thirdname</disk1>
</disk>
<map>
<code>1</code>
</map>
<map>
<code>2</code>
</map>
</storage>
</start>
所以它在每次出现“ disk&gt; ”之后都会放入Bfile的内容。我只需要最后一次出现。如何更改命令?
答案 0 :(得分:3)
我没有设法在一行中做到这一点所以我做了一个sed脚本。问题是如果文件名后面有字符,则r
命令将不起作用,因此它需要在它自己的行上。
#!/bin/sed -f
/<\/disk>/{
:a
n
s/disk/disk/
t a
h
r bbb
g
N
}
然后你可以这样称呼它:
sed -f sedscript Afile
答案 1 :(得分:3)
XML(与一般的结构化数据一样)不应该使用纯文本工具来处理,例如awk
和sed
,除非是非常特殊的情况,因为没有人希望XML工具在新行更改时中断在良性场所插入/移除地点或空间。
相反,我使用的是Python,它的标准库中有一个XML解析器:
#!/usr/bin/python
import xml.etree.ElementTree as ET;
import sys;
# file names taken from command line arguments.
target = ET.parse(sys.argv[1]);
insert = ET.parse(sys.argv[2]);
# Interesting part here:
target.getroot().find("./storage").append(insert.getroot())
# to write to a file, use target.write('output.xml')
ET.dump(target)
将其称为
python foobar.py fileA fileB
答案 2 :(得分:2)
如果受到存储限制(给出的第一个样本)
sed '\#</storage># {r Bfile
N;} ' Afile
如果存储中的最后磁盘(如此请求的编辑版本)
sed '1;\#<storage>#{1h;1!H
\#<storage># {g
s#^\(.*\n</disk>\).*#\1#p
r Bfile
G;N
s/^\(.*\)\1\(.*\)/\2/
}
}' Afile
在r
操作之后,Normaly将脚本循环到下一行(并且没有读取此行的其余脚本)但是在N
之后,它继续并将该行保留在缓冲区中以便进行操作(在这种情况下,下一个)。
所以只有在存储之后有一条线时才能工作(在这种情况下可以使用if / the / else动作添加测试)
答案 3 :(得分:2)
只是使用AWK添加一些示例。
假设我们有:
<强>å文件强>:
<start>
<memory>
<hdd>10</hdd>
<hdc>40</hdc>
</memory>
<storage>
<disk>
<disk1>firstname</disk1>
</disk>
<disk>
<disk1>secondname</disk1>
</disk>
</storage>
</start>
和 bfile :
<disk>
<disk1>thirdname</disk1>
</disk>
AWK使用</storage>
标记作为参考:
awk '/^<\/storage>/{while(getline line<"bfile"){print line};print;next}1' afile
这将导致:
<start>
<memory>
<hdd>10</hdd>
<hdc>40</hdc>
</memory>
<storage>
<disk>
<disk1>firstname</disk1>
</disk>
<disk>
<disk1>secondname</disk1>
</disk>
<disk>
<disk1>thirdname</disk1>
</disk>
</storage>
</start>
但是如果您真的需要寻找</disk>
,我会做类似的事情:
awk -v n=4 '{print;}/<\/disk1>$/,/^<\/disk>/{m++}(m==n){n=0;while(getline l<"bfile"){print l}}' afile
此外,您还可以使用xmllint
为您输出格式:
awk -v n=4 '{print;}/<\/disk1>$/,/^<\/disk>/{m++}(m==n){n=0;while(getline l<"bfile"){print l}}' afile | xmllint --format --recover -
这将导致:
<start>
<memory>
<hdd>10</hdd>
<hdc>40</hdc>
</memory>
<storage>
<disk>
<disk1>firstname</disk1>
</disk>
<disk>
<disk1>secondname</disk1>
</disk>
<disk>
<disk1>thirdname</disk1>
</disk>
</storage>
</start>
答案 4 :(得分:0)
如果ed
是一个选项(如果输入文件不是太大),那就更容易了:
echo '/map/-1 r Bfile
wq' | ed Afile
答案 5 :(得分:0)
这可能适合你(GNU sed):
sed -e '/<disk>/,${/<disk>/,/<\/disk>/b;ecat fileb' -e ':a;n;ba}' filea
这会将sed命令限制为以<disk>
开头的那些行到文件的末尾。在此范围内,所有完整的<disk>
/ <\/disk>
标记都会照常打印。以下行是要插入文件的位置,并使用sed evalute命令立即插入文件(而不是使用在当前模式空间之后插入文件的r
命令)。然后使用简单的循环打印文件的其余部分。