我希望迭代一个与XML文件中的ID号匹配的ID号列表,并使用BASH(和AWK)将下面的行打印到shell或将其重定向到第三个输出文件(output.txt) )
以下是细分:
ID_list.txt(此示例缩写 - 它有100个ID)
4414
4561
2132
999
1231
34
489
3213
7941
XML_example.txt(数千个条目)
<book>
<ID>4414</ID>
<name>Name of first book</name>
</book>
<book>
<ID>4561</ID>
<name>Name of second book</name>
</book>
我希望脚本的输出是第一个文件中100个ID的名称:
Name of first book
Name of second book
etc
我相信可以使用BASH和AWK使用for循环(对于文件1中的每个,在file2中找到相应的名称)。我认为您可以为ID编号重新设置GREP,然后使用AWK打印它下面的行。即使输出看起来像这样,我也可以删除XML标签:
<name>Name of first book</name>
<name>Name of second book</name>
它位于Linux服务器上,但我可以将其移植到Windows上的PowerShell。我认为BASH / GREP和AWK是可行的方法。
有人可以帮我编写脚本吗?
答案 0 :(得分:3)
给定ID,您可以使用XPath xpressions和xmllint
命令获取名称,如下所示:
id=4414
name=$(xmllint --xpath "string(//book[ID[text()='$id']]/name)" books.xml)
因此,你可以这样写:
while read id; do
name=$(xmllint --xpath "string(//book[ID[text()='$id']]/name)" books.xml)
echo "$name"
done < id_list.txt
与涉及awk
,grep
和朋友的解决方案不同,这是正在使用的
一个实际的XML解析工具。这意味着虽然大多数其他
如果遇到以下问题,解决方案可能会中断:
<book><ID>4561</ID><name>Name of second book</name></book>
......这样做会很好。
xmllint
是libxml2
包的一部分,大多数都可用
分布。
另请注意,最新版本的awk有native XML parsing。
答案 1 :(得分:1)
$ awk '
NR==FNR{ ids["<ID>" $0 "</ID>"]; next }
found { gsub(/^.*<name>|<[/]name>.*$/,""); print; found=0 }
$1 in ids { found=1 }
' ID_list.txt XML_example.txt
Name of first book
Name of second book
答案 2 :(得分:1)
这是一种方式:
while IFS= read -r id
do
grep -A1 "<ID>$id</ID>" XML_example.txt | grep "<name>"
done < ID_list.txt
这是另一种方式(单线)。这样更有效,因为它使用单个grep来提取所有id而不是循环:
egrep -A1 $(sed -e 's/^/<ID>/g' -e 's/$/<\/ID>/g' ID_list.txt | sed -e :a -e '$!N;s/\n/|/;ta' ) XML_example.txt | grep "<name>"
输出:
<name>Name of first book</name>
<name>Name of second book</name>
答案 3 :(得分:0)
如果必须以bash
进行,我会去BASH_REMATCH
路线
BASH_REMATCH
An array variable whose members are assigned by the =~ binary
operator to the [[ conditional command. The element with index
0 is the portion of the string matching the entire regular
expression. The element with index n is the portion of the
string matching the nth parenthesized subexpression. This vari‐
able is read-only.
如下所示
#!/bin/bash
while read -r line; do
[[ $print ]] && [[ $line =~ "<name>"(.*)"</name>" ]] && echo "${BASH_REMATCH[1]}"
if [[ $line == "<ID>"*"</ID>" ]]; then
print=:
else
print=
fi
done < "ID_list.txt"
示例输出
> abovescript
Name of first book
Name of second book