我有两个文件a。)xmlFile.xml b。)emails.txt
xmlFile.xml具有多次重复的以下结构
<gname>Office</gname>
<uname>person</uname>
emails.txt包含电子邮件地址列表
email1@company.com
email2@company.com
...
我想要完成的是将xmlFile.xml中的“person”替换为来自emails.txt的后续值
我试过了
# while read email ; do sed "s/person/$email/g" xmlFile.xml > xmlFile.new; done < emails.txt
但是我最终使用的文件将所有“person”值替换为来自emails.txt的最后一封电子邮件
谢谢, 菲利普
答案 0 :(得分:3)
awk 'NR==FNR{e[i++]=$0;next} /person/{sub("person",e[j++])}1' emails.txt xmlFile.xml
NR==FNR
:仅当awk
正在读取第一个文件时才会出现这种情况。它主要测试所看到的记录总数(NR)与当前文件(FNR)中的输入记录。e[i++]=$0
:创建一个名为 e 的数组,其索引的增量为1(i++
),其值等于当前记录$0
。这个数组将保存我们的电子邮件next
:如果达到此目的,请忽略脚本的其余部分,重新开始使用新的输入记录/person/
:如果当前记录与正则表达式“person”匹配,则仅执行后续代码sub("person",e[j++])
:将字面值“person”替换为我们之前创建的数组 e 中的值。为我们匹配的下一条记录增加此数组j++
{print $0}
的快捷方式,或输出我们当前的记录$ cat emails.txt
email1@company.com
email2@company.com
email3@company.com
email4@company.com
email5@company.com
email6@company.com
email7@company.com
email8@company.com
email9@company.com
$ cat xmlFile.xml
<gname>Office</gname>
<uname>person</uname>
<gname>Office</gname>
<uname>person</uname>
<gname>Office</gname>
<uname>person</uname>
<gname>Office</gname>
<uname>person</uname>
<gname>Office</gname>
<uname>person</uname>
<gname>Office</gname>
<uname>person</uname>
<gname>Office</gname>
<uname>person</uname>
<gname>Office</gname>
<uname>person</uname>
<gname>Office</gname>
<uname>person</uname>
$ awk 'NR==FNR{e[i++]=$0;next} /person/{sub("person",e[j++])}1' emails.txt xmlFile.xml
<gname>Office</gname>
<uname>email1@company.com</uname>
<gname>Office</gname>
<uname>email2@company.com</uname>
<gname>Office</gname>
<uname>email3@company.com</uname>
<gname>Office</gname>
<uname>email4@company.com</uname>
<gname>Office</gname>
<uname>email5@company.com</uname>
<gname>Office</gname>
<uname>email6@company.com</uname>
<gname>Office</gname>
<uname>email7@company.com</uname>
<gname>Office</gname>
<uname>email8@company.com</uname>
<gname>Office</gname>
<uname>email9@company.com</uname>
上述脚本假定person
是字面值。如果不是,那么..
替换:/person/{sub("person",emails[j++])}
使用:/<uname>/{sub(".*","<uname>"emails[j++]"</uname>")}
答案 1 :(得分:1)
实现这一目标的一种方法是使用就地编辑:
while read email ; do sed -i "s/person/$email/;q" xmlFile.xml; done < emails.txt
如果XML文件很少或没有比您显示的更多,只需重新构建它:
sed -e 'i <gname>Office</gname>' -e 's|.*|<uname>&</uname>|' emails.txt > newxmlFile.xml
甚至没有触及现有的xmlFile.xml
。
但是,您应该使用XML解析器,例如xmlstarlet
。
答案 2 :(得分:0)
以下是如何使用bash&amp; amp; xmlstarlet!
IFS=$'\n' read -r -d "" -a array < emails.txt # read file with email addresses into array
n=$(xmlstarlet sel -T -t -v "count(//uname)" -n xmlFile.xml) # count "uname" nodes in XML file
xmlFileStr="$(< xmlFile.xml)" # read XML file into variable
if [[ $n -eq ${#array[@]} ]]; then # if the number of nodes & email addresses is equal ...
for ((i=1; i <= ${n}; i+=1)); do
xmlFileStr="$(printf '%s' "$xmlFileStr" | xmlstarlet ed -P -t -u "//uname[${i}]" -v "${array[$((i-1))]}")"
done
fi
printf '%s\n' "$xmlFileStr" > xmlFile.xml
cat xmlFile.xml