【问题标题】:Delete nodes from xml file using sed or awk使用 sed 或 awk 从 xml 文件中删除节点
【发布时间】:2021-03-22 11:20:11
【问题描述】:

我希望使用 sed 或 awk 实用程序从多个相似的 XML 文件中删除“error_mail”和“succeed_mail”节点。

使用 sed ,我尝试使用以下命令..但它不起作用

sed -i /<action name="succeed_mail">/,/<\/action>/d *.xml

这里是示例文件(test.xml),如下所示:-

输入 XML 文件:- test.xml

 <workflow>
    <action name="start"
    -----
    -----
       </action>
    
    <action name="error_mail">
            <email xmlns="uri:oozie:email-action:0.1">
              <to>abc@xyz.com</to>
              <cc>abc@xyz.com</cc>
              <subject>Batch Failed</subject>
              <body>Batch Failed at ${node}</body>
            </email>
            <ok to="killjob"/>
            <error to="killjob"/>
          </action>
        <action name="succeed_mail">
            <email xmlns="uri:oozie:email-action:0.1">
              <to>abc@xyz.com</to>
              <cc>abc@xyz.com</cc>
              <subject>Batch Succeed</subject>
              <body>Batch completed</body>
            </email>
            <ok to="end"/>
            <error to="end"/>
          </action></r>
    </workflow>

--------所需的输出:-

test.xml
<workflow>
<action name="start"
-----
-----
   </action>
</workflow>

【问题讨论】:

  • 始终将脚本括在引号中:sed 'foo',而不是 sed foo。此外,“它不工作”是最糟糕的问题陈述 - 告诉我们它以何种方式不工作(错误输出、无输出、错误消息等),以便我们可以最好地帮助您解决您遇到的问题,而不是可能的一些问题我们认为您可能遇到的其他问题。

标签: awk sed


【解决方案1】:

有类似的需求。我的过程:

  1. 将 xml 转换为单行。
  2. 在自己的新行中将&lt;tag&gt; 转换为&lt;/tag&gt;
  3. grep -v tag(或需要的字符串)
  4. xmllint --format
  5. qed

这个方法很通用。 要将 xml 转换为单行:tr -d '\n' 第 2 步的 Csh 脚本,接受来自管道标准输入的 xml

>cat xmlsinglenewline
#!/bin/csh -f
# $1 is the tag
# Usage: <command>  "tag"
sed "s/<$1/\n\<$1/g" | sed "s/<\/$1>/\<\/$1\>\n/g"

警告: 无法处理嵌套(相同)标签。

【讨论】:

    【解决方案2】:

    你没有告诉我们“它不工作”的方式,所以我假设你要么不知道如何在正则表达式中使用 |,要么不知道你必须引用你的脚本。

    使用具有-E 的 sed 来启用 ERE:

    $ sed -E '/<action name="(succeed|error)_mail">/,/<\/action>/d' file
     <workflow>
        <action name="start"
        -----
        -----
           </action>
    
        </workflow>
    

    或使用任何 awk:

    $ awk '/<action name="(succeed|error)_mail">/{f=1} !f; /<\/action>/{f=0}' file
     <workflow>
        <action name="start"
        -----
        -----
           </action>
    
        </workflow>
    

    当然,这很脆弱,并且对于同一 XML 的各种其他布局会失败,这就是为什么总是建议使用 XML 感知工具的原因。

    【讨论】:

      【解决方案3】:

      专家总是建议使用 xmlstarlet 之类的工具来解析 xml 文件,因为 OP 正在使用 sed,所以提出了这个 awk 解决方案。公平警告,仅根据所示示例编写,以防万一您有不同的内容,这可能不起作用。

      awk '
      /^ +<\/action>/ && foundSuccess{
        foundSuccess=""
        next
      }
      /^ +<\/action>/ && foundError{
        foundError=""
        next
      }
      /^ +<action name="error_mail">$/{
        foundError=1
      }
      /^ +<action name="succeed_mail">/{
        foundSuccess=1
      }
      NF && !foundError && !foundSuccess
      ' Input_file
      

      说明:为上述添加详细说明。

      awk '                              ##Starting awk program from here.
      /^ +<\/action>/ && foundSuccess{   ##Checking if line has </action> and variable foundSuccess is SET then do following.
        foundSuccess=""                  ##Nullify variable foundSuccess here.
        next                             ##next will skip all further statements from here.
      }
      /^ +<\/action>/ && foundError{     ##Checking if line has </action> and variable foundError is SET then do following.
        foundError=""                    ##Nullify variable foundError here.
        next                             ##next will skip all further statements from here.
      }
      /^ +<action name="error_mail">$/{  ##Checking if line starts with space and have <action name="error_mail">
        foundError=1                     ##Setting variable foundError to 1 here.
      }
      /^ +<action name="succeed_mail">/{ ##Checking if line starts with space and have <action name="succeed_mail">
        foundSuccess=1                   ##Setting variable foundSuccess to 1 here.
      }
      NF && !foundError && !foundSuccess ##Checking if line is NOT empty AND variable foundError AND variable foundSuccess is NOT set then print that line.
      ' Input_file                       ##Mentioning Input_file name here.
      

      注意:要传递多个 xml 文件来代替 Input_file,请使用 *.xml 给它,但这不会就地保存。要执行就地保存使用 GNU awk,请将上述代码中的 awk 更改为 awk -i inplace 。但最好在几个文件上测试它,然后运行就地选项,以确保更安全。您可以查看此链接如何使用 awk 进行就地编辑,同时备份 Input_file https://stackoverflow.com/a/16529730/5866580

      【讨论】:

      • 感谢@RavinderSingh13!它抛出错误。 awk -i inplace ' > /^ +/ && foundSuccess{ > foundSuccess="" > next > } > /^ +/ && foundError{ > foundError="" > next > } > /^ +$/{ > foundError=1 > } > /^ +/{ > foundSuccess=1 > } > NF && !foundError && !foundSuccess > ' redraw_workflow_curve2.xml 用法:awk [POSIX or GNU style options] -f progfile [--] file ... 用法:awk [POSIX or GNU style options] [--] 'program' file ...
      • @PraveenKumar,当我检查单个文件时,它工作得非常好。由于您的 cmets 错误不清楚,请清楚地复制/粘贴并尝试在单个文件上测试一次,然后让我知道。
      • @PraveenKumar &gt; 在您评论中脚本的每一行开头做了什么?
      • @PraveenKumar,您好 Praveen,请检查我和 Ed sir 的回答,让我们知道进展如何?
      猜你喜欢
      • 2023-03-05
      • 2017-04-10
      • 2016-03-28
      • 2014-03-10
      • 2016-02-04
      • 2018-10-31
      • 2013-10-08
      • 1970-01-01
      • 2023-01-26
      相关资源
      最近更新 更多