如何解决解析xml和文本文件以删除shell中的通配符
我有一个带有这样输入的xml文件。我正在尝试编写一个Shell脚本来删除主机中的通配符。
<Group>
<GroupEntry groupname="aM"/>
<GroupSubjectEntry host="*" name="root"/>
<GroupSubjectEntry host="*" name="apro"/>
<GroupSubjectEntry host="*" name="rock"/>
</Group>
<Group>
<GroupEntry groupname="ESB"/>
<GroupSubjectEntry host="*" name="esbsvc"/>
<GroupSubjectEntry host="*" name="retryt"/>
</Group>
<Group>
<GroupEntry groupname="Omega"/>
<GroupSubjectEntry host="*" name="omegauser"/>
</Group>
</GroupSet>
我有一个文本文件,其中包含每个组名的主机名,如下所示。
aM
hostname1
hostname2
ESB
hostname3
hostname4
Omega
hostname5
hostname6
hostname7
hostname8
hostname1
我正在尝试解析/遍历文本文件并更改xml文件以删除通配符。所以,我想要得到的结果是
<Group>
<GroupEntry groupname="aM"/>
<GroupSubjectEntry host="hostname1" name="root"/>
<GroupSubjectEntry host="hostname1" name="apro"/>
<GroupSubjectEntry host="hostname1" name="rock"/>
<GroupSubjectEntry host="hostname2" name="root"/>
<GroupSubjectEntry host="hostname2" name="apro"/>
<GroupSubjectEntry host="hostname2" name="rock"/>
</Group>
<Group>
<GroupEntry groupname="ESB"/>
<GroupSubjectEntry host="hostname3" name="esbsvc"/>
<GroupSubjectEntry host="hostname3" name="retryt"/>
<GroupSubjectEntry host="hostname4" name="esbsvc"/>
<GroupSubjectEntry host="hostname4" name="retryt"/>
</Group>
<Group>
<GroupEntry groupname="Omega"/>
<GroupSubjectEntry host="hostname5" name="omegauser"/>
<GroupSubjectEntry host="hostname6" name="omegauser"/>
<GroupSubjectEntry host="hostname7" name="omegauser"/>
<GroupSubjectEntry host="hostname8" name="omegauser"/>
<GroupSubjectEntry host="hostname1" name="omegauser"/>
</Group>
</GroupSet>
我尝试使用sed和awk作为以下示例
sed '/GroupSubjectEntry host="\*"/p' omegatest.xml|sed '0,/\*/s//host/'
,但这只是更改第一行。
我想到了通过for loop
并使用sed p
选项运行此操作,但是涉及的变量太多。我基本上是想删除xml中的通配符以添加适当的主机名。
有人可以帮忙吗?
解决方法
请您尝试使用GNU awk
进行以下操作,编写和测试。建议使用公平的警告工具(例如-> xmlstarlet
)来处理xml,因为OP不能使用它们,也不能使用那些,因此不能保证它可以与所有xml一起使用,这仅严格地用于显示的示例。
第一个解决方案: 根据OP的预期输出:
awk '
!NF{ next }
FNR==NR{
if($0 ~ /GroupEntry groupname="/){
match($0,/"[^"]*/)
val=substr($0,RSTART+1,RLENGTH-1)
match($0,/^ +/)
spaces[val]=substr($0,RSTART,RLENGTH)
namesVal[val]=$0
next
}
if($0 ~ /<GroupSubjectEntry host=/){
match($0,/name="[^"]*/)
names[val]=(names[val]?names[val] ORS:"")substr($0,RSTART+6,RLENGTH-6)
next
}
if($0~/<Group>/ || $0~/<\/Group>/){
rest[++count1]=$0
}
next
}
!/hostname/{
if($0 in names){
nameVal=namesVal[$0]
check=$0
if(FNR==1){ print rest[++count2];found="" }
print namesVal[$0]
num=split(names[$0],arr,"\n")
}
if(found){ print rest[++count2];found="" }
}
/^hostname/{
found=1
for(i=1;i<=num;i++){
print spaces[check] "<GroupSubjectEntry host=\"" $0"\" name=\""arr[i]"\"/>"
}
next
}
END{
print rest[count2]
}
' Input_file groupnames
第二种解决方法: 如果OP不会打扰实际输入文件中的名称序列,那么可以尝试遵循。
awk '
FNR==NR{
if(!NF){ next }
if($0!~/^hostname/){ val=$0 }
else { arr[val]=(arr[val]?arr[val] ORS:"")$0 }
next
}
/<GroupEntry groupname=/ && match($0,/".*"/){
val=substr($0,RLENGTH-2)
}
/GroupSubjectEntry host=/{
match($0,/^ +/)
spaces=substr($0,RLENGTH)
match($0,/name="[^"]*/)
name=substr($0,RLENGTH-6)
num=split(arr[val],arr1,"\n")
for(i=1;i<=num;i++){
print spaces "<GroupSubjectEntry host=\"" arr1[i]"\" name=\""name"\"/>"
}
next
}
1' groupnames Input_file
这也会按hostnames
的顺序给出输出,并带有相应的组名,我希望OP可以正常使用。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。