使用bash脚本从XML文件中提取特定关键字
我有一个XML文件,其中包含一些以特定单词为特征的条目。 我需要对条目运行for循环,为每个条目提取两个不同的关键字,以便在for循环中用作变量使用bash脚本从XML文件中提取特定关键字,xml,linux,bash,awk,sed,xidel,Xml,Linux,Bash,Awk,Sed,Xidel,我有一个XML文件,其中包含一些以特定单词为特征的条目。 我需要对条目运行for循环,为每个条目提取两个不同的关键字,以便在for循环中用作变量 $ eval $(xidel -s list.xml -e ' //data-set/( eval(x"{concat("pn",position())}:=element[@name=""PatientName""]")[0], eval(x"
$ eval $(xidel -s list.xml -e '
//data-set/(
eval(x"{concat("pn",position())}:=element[@name=""PatientName""]")[0],
eval(x"{concat("si",position())}:=element[@name=""StudyInstanceUID""]")[0]
)
' --output-format=bash)
$ printf '%s\n' $pn1 $si1 $pn2 $si2
Anon^1600373003
1.3.76.13.99972.2.20181217085753.1484038.1
Anon^1599844862
1.3.76.13.99972.2.20180925142630.1456727.1
下面是list.xml的一个示例:
ISO_IR 192
学习
柏拉图
第160037303页
1.3.76.13.99972.2.20181217085753.1484038.1
ISO_IR 192
学习
柏拉图
Anon^1599844862
1.3.76.13.99972.2.20180925142630.1456727.1
我需要提取关键词“PatientName”和“StudyInstanceUID”。
我试着用这样的方法:
grep -A2 -i "PatientName" list.xml | while read -r string ; do
PatientName="$(echo $string | grep -i "PatientName" | cut -d ">" -f 2 | cut -d "<" -f 1)"
StudyInstanceUID="$(echo $string | grep -i "StudyInstanceUID" | cut -d ">" -f 2 | cut -d "<" -f 1)"
echo "$PatientName"
echo "$StudyInstanceUID"
done
Anon^1600373003
1.3.76.13.99972.2.20181217085753.1484038.1
Anon^1599844862
1.3.76.13.99972.2.20180925142630.1456727.1
非常感谢
伊万命令:
grep -A2 -i "PatientName" list.xml
返回多行:
<element tag="0010,0010" vr="PN" vm="1" len="16" name="PatientName">Anon^1600373003</element>
<element tag="0020,000d" vr="UI" vm="1" len="42" name="StudyInstanceUID">1.3.76.13.99972.2.20181217085753.1484038.1</element>
</data-set>
--
<element tag="0010,0010" vr="PN" vm="1" len="16" name="PatientName">Anon^1599844862</element>
<element tag="0020,000d" vr="UI" vm="1" len="42" name="StudyInstanceUID">1.3.76.13.99972.2.20180925142630.1456727.1</element>
</data-set>
StudyInstanceUID
不存在,变量将为空
为了获得所需的结果,请尝试以下操作:
grep -A1 -i "PatientName" list.xml | while read -r string ; do
PatientName="$(echo $string | grep -i "PatientName" | cut -d ">" -f 2 | cut -d "<" -f 1)"
read string
StudyInstanceUID="$(echo $string | grep -i "StudyInstanceUID" | cut -d ">" -f 2 | cut -d "<" -f 1)"
echo "$PatientName"
echo "$StudyInstanceUID"
read string
done
grep-A1-i“PatientName”list.xml |而read-r字符串;做
PatientName=“$(echo$string | grep-i“PatientName”| cut-d“>”-f2 | cut-d“--f2 | cut-d”,正如Raman在评论中所提到的,使用XML感知工具解析XML数据可能是最好的选择,尤其是当您的一些XML可能没有问题中显示的格式时(例如,一条长线上的所有内容)
假设:
- 您可以确认所有数据的格式与问题中的示例相同(即,每个元素位于单独的行上)
- 搜索字符串
PatientName
和StudyInstanceUID
不会以较大的字符串显示(例如,LastPatientName
或PreviousStudyInstanceUID
)
PatientName
元素始终列在StudyInstanceUID
元素之前
一个awk
解决方案,消除了对echo
、grep
和cut
的所有子进程调用的需要:
awk -F'[<>]' ' # define input field separators as "<" and ">"
/PatientName/ || /StudyInstanceUID/ { print $3 } # if we find one of our search strings then print field #3
' list.xml
至于将输出捕获到变量中(例如,在while
循环中),我们可以进行一些小的更改,例如:
awk -F'[<>]' '
/PatientName/ { pn=$3 } # store field #3 in variable "pn"
/StudyInstanceUID/ { printf "%s %s\n", pn, $3 } # print data to stdout
' list.xml
将其送入while
循环:
while read -r PatientName StudyInstanceUID
do
echo "+++++++++++++++++++"
echo "PatientName: ${PatientName}"
echo "StudyInstanceUID: ${StudyInstanceUID}"
done < <(awk -F'[<>]' ' /PatientName/ { pn=$3 } /StudyInstanceUID/ { printf "%s %s\n", pn, $3 } ' list.xml)
awk
和sed
不是为处理XML而设计的。请使用专用工具。我可以推荐
Stdout:
$ xidel -s list.xml -e '
//data-set/(
element[@name="PatientName"],
element[@name="StudyInstanceUID"]
)
'
Anon^1600373003
1.3.76.13.99972.2.20181217085753.1484038.1
Anon^1599844862
1.3.76.13.99972.2.20180925142630.1456727.1
$ xidel -s list.xml -e '
//data-set/(
eval(x"{concat("pn",position())}:=element[@name=""PatientName""]")[0],
eval(x"{concat("si",position())}:=element[@name=""StudyInstanceUID""]")[0]
)
'
pn1 := Anon^1600373003
si1 := 1.3.76.13.99972.2.20181217085753.1484038.1
pn2 := Anon^1599844862
si2 := 1.3.76.13.99972.2.20180925142630.1456727.1
变量:
$ xidel -s list.xml -e '
//data-set/(
element[@name="PatientName"],
element[@name="StudyInstanceUID"]
)
'
Anon^1600373003
1.3.76.13.99972.2.20181217085753.1484038.1
Anon^1599844862
1.3.76.13.99972.2.20180925142630.1456727.1
$ xidel -s list.xml -e '
//data-set/(
eval(x"{concat("pn",position())}:=element[@name=""PatientName""]")[0],
eval(x"{concat("si",position())}:=element[@name=""StudyInstanceUID""]")[0]
)
'
pn1 := Anon^1600373003
si1 := 1.3.76.13.99972.2.20181217085753.1484038.1
pn2 := Anon^1599844862
si2 := 1.3.76.13.99972.2.20180925142630.1456727.1
这些是刚刚打印到stdout的内部变量。使用--output format=bash
和bash的内置eval
命令将它们转换为shell变量
$ eval $(xidel -s list.xml -e '
//data-set/(
eval(x"{concat("pn",position())}:=element[@name=""PatientName""]")[0],
eval(x"{concat("si",position())}:=element[@name=""StudyInstanceUID""]")[0]
)
' --output-format=bash)
$ printf '%s\n' $pn1 $si1 $pn2 $si2
Anon^1600373003
1.3.76.13.99972.2.20181217085753.1484038.1
Anon^1599844862
1.3.76.13.99972.2.20180925142630.1456727.1
使用像XMLLinTech这样的专用工具只是一个例子,我需要在bash脚本中实现它,以使用关键字执行其他操作。@I.Iudice-当你说“我需要提取关键字”PatientName“和”StudyInstanceUID“时,你不清楚你的意思。你实际上想实现什么?是为了实现吗例如,将Anon^1600373003
和Anon^1599844862
分配给PatientName
变量,同样地将1.3.76.13.99972.2.20181217085753.1484038.1
和1.3.76.13.99972.20180925142630.1456727.1
分配给StudyInstanceUID
变量。B) 或者,只需将结果打印(回显)到控制台,就像您显示的那样?3) 或者别的什么?我一直在努力实现A),我必须使用这些变量来运行信号处理算法;我用Xmlet管道代替了awk管线,效果很好。谢谢!
$ xidel -s list.xml -e '
//data-set/(
eval(x"{concat("pn",position())}:=element[@name=""PatientName""]")[0],
eval(x"{concat("si",position())}:=element[@name=""StudyInstanceUID""]")[0]
)
'
pn1 := Anon^1600373003
si1 := 1.3.76.13.99972.2.20181217085753.1484038.1
pn2 := Anon^1599844862
si2 := 1.3.76.13.99972.2.20180925142630.1456727.1
$ eval $(xidel -s list.xml -e '
//data-set/(
eval(x"{concat("pn",position())}:=element[@name=""PatientName""]")[0],
eval(x"{concat("si",position())}:=element[@name=""StudyInstanceUID""]")[0]
)
' --output-format=bash)
$ printf '%s\n' $pn1 $si1 $pn2 $si2
Anon^1600373003
1.3.76.13.99972.2.20181217085753.1484038.1
Anon^1599844862
1.3.76.13.99972.2.20180925142630.1456727.1