【问题标题】:Parse xml and a text file to remove wildcards in shell解析 xml 和文本文件以删除 shell 中的通配符
【发布时间】:2020-12-29 02:21:25
【问题描述】:

我有一个带有这样输入的 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 中的通配符以添加适当的主机名。 有人可以帮忙吗?

【问题讨论】:

  • 恕我直言,专家总是建议使用xmlstarlet 之类的工具来解析 xml 文件,所以请告诉我们您的盒子里是否有该工具或者您可以安装它。如果您无法安装,我们可以提供相应的解决方案。
  • @RavinderSingh13 感谢您的回复。看起来我没有那个。而且我可能无法在我的服务器上安装它。
  • 好的,感谢您在这里确认。还有一件事你在组名文件aM 中的第一行应该在那里对吗?能否请您确认一次。从hostname 开始的行是否真的从主机名开始?为什么要问这个,因为我们需要一些逻辑来从文件中选择值,所以想在这里与您核实。
  • @RavinderSingh13 抱歉。那是一个错字。我已经纠正了。如果它使您的逻辑更容易,我们有我们想要的文本文件。但主机名必须归入正确的组。

标签: xml bash shell awk sed


【解决方案1】:

您能否尝试使用 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,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 没问题。

【讨论】:

    猜你喜欢
    • 2021-08-10
    • 1970-01-01
    • 1970-01-01
    • 2014-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多