分析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中的通配符,以添加适当的主机名。有人能帮忙吗?

您能尝试以下内容吗?这些内容是用GNUawk编写和测试的。公平的警告工具,例如-->建议使用xmlstarlet来处理xml,因为OP不能使用这些xml,也没有这些xml,所以这篇文章附带了这些xml,但不能保证这篇文章适用于所有类型的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,RSTART+1,RLENGTH-2)
}
/GroupSubjectEntry host=/{
match($0,/^ +/)
spaces=substr($0,RSTART,RLENGTH)
match($0,/name="[^"]*/)
name=substr($0,RSTART+6,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可以接受

最新更新