【问题标题】:Extract text between two string and perform operation on it提取两个字符串之间的文本并对其执行操作
【发布时间】:2015-03-22 00:43:54
【问题描述】:

我有一个包含以下文本的文件

<MY_TEXT="XYZ" PATH="MNO"       #First occurrence of MY_TEXT
<location= "XYZ" path="ABC"
\location>
<R_DATA = MNOP
<Mylocation ="ghdf" stime=20150301 etime=20150401 >
<Mylocation ="ghdf" stime=20150401 etime=20150501 >
\R_DATA>
<Blah>
\MY_TEXT>                       #Second occurrence of MY_TEXT
<MY_TEXT="ABC" PATH="EFG"       #Third occurrence of MY_TEXT
<location= "QQQ" path="LLL"
\location>
<R_DATA = MNOP     
<Mylocation ="ghdf" stime=20150301 etime=20150401 >
<Mylocation ="ghdf" stime=20150401 etime=20150501 >
\R_DATA>
<Blah>
\MY_TEXT>         #Fourth occurrence of MY_TEXT

我的任务是在行中找到一个包含&lt;MY_TEXT="XYZ" 的文本,它的开头可能有空格,然后找到它的结尾\MY_TEXT 所以输出有点

<MY_TEXT="XYZ" PATH="MNO"       #First occurrence of MY_TEXT
<location= "XYZ" path="ABC"
\location>
<R_DATA = MNOP
<Mylocation ="ghdf" stime=20150301 etime=20150401 >  #First occurrence of Mylocation
<Mylocation ="ghdf" stime=20150401 etime=20150501 >  #Second occurrence of Mylocation
\R_DATA>
<Blah>
\MY_TEXT>

然后它在此处找到最后一次出现的 Mylocation 即 #Second occurrence of Mylocation 并将文本 etime=20150501 修改为 something 并在文件中内联后附加一个新行。

我遇到了这个链接Sed to extract text between two strings。但在这里使用 sed 命令要么让我 当我使用 -n 选项时什么都没有,或者当我删除 -n 时打印整个文件。 所以我无法进一步处理文本,因为我无法提取我想要的文本。

我也试过 sed -n '/^ *START=A *$/,/^ *END *$/p' yourfile 。但是没有用。你们能帮我吗,因为我的脚本不是很好。提前致谢。

【问题讨论】:

    标签: bash awk sed


    【解决方案1】:

    这对 sed 来说有点棘手,但我会尝试一下。

    重要提示:这看起来像是一种定义明确的文件格式,但我不认识它。谨慎的做法是查看是否有工具可以直接处理这种格式,而不是像 sed 那样将其视为平面文件。这样的解决方案很可能比直接文本黑客更短、更容易理解、更健壮。

    也就是说,你可以使用

    sed -n '/<MY_TEXT="XYZ"/ { :a /\\MY_TEXT>/! { N; ba }; s/\(.*\)\(<Mylocation\)/\1\\MY_TEXT>\n\2/; h; s/.*\\MY_TEXT>\n//; s/etime=[0-9]\+/etime=something/; s/\n/\n\n/; s/$/\\MY_TEXT>/; G; s/\(.*\)\\MY_TEXT>\n\(.*\)\\MY_TEXT>\n\(.*\)/\2\1/; p }' filename
    

    输出:

    <MY_TEXT="XYZ" PATH="MNO"       #First occurrence of MY_TEXT
    <location= "XYZ" path="ABC"
    \location>
    <R_DATA = MNOP
    <Mylocation ="ghdf" stime=20150301 etime=20150401 >
    <Mylocation ="ghdf" stime=20150401 etime=something >
    
    \R_DATA>
    <Blah>
    \MY_TEXT>
    

    其中最令人困惑的一点是使用\MY_TEXT&gt;\n 作为标记来分隔工作块;这样做是因为我们知道它不会出现在文本的其他任何地方。 \MY_TEXT&gt; 首先出现在我们正在处理的块的最后一行,因此在输入数据中永远不会有换行符。 (代码中没有出现在文本中的其他内容可能会更清晰,但我不知道有什么更明显的东西)。

    代码工作如下:

    #!/bin/sed -nf
    
    /<MY_TEXT="XYZ"/ {                                    # If we find the starter
                                                          # line:
      :a
      /\\MY_TEXT>/! {                                     # fetch the rest of the
        N                                                 # block into the
        ba                                                # pattern space
      }
      s/\(.*\)\(<Mylocation\)/\1\\MY_TEXT>\n\2/           # mark the place before
                                                          # the last Mylocation tag
      h                                                   # copy that to the hold
                                                          # buffer
      s/.*\\MY_TEXT>\n//                                  # remove the stuff before
                                                          # the marker
      s/etime=[0-9]\+/etime=something/                    # replace  the etime
                                                          # attribute
      s/\n/\n\n/                                          # insert the new line
      s/$/\\MY_TEXT>/                                     # put a marker at the end
      G                                                   # fetch back the stuff
                                                          # from the hold buffer
      s/\(.*\)\\MY_TEXT>\n\(.*\)\\MY_TEXT>\n\(.*\)/\2\1/  # replace the end chunk
                                                          # with the edited version
      p                                                   # print the result.
    }
    

    【讨论】:

    • 这是一段很棒的 sed,你已经把它解释得最好了。但它错过了我最后一个要求,即在文件中最后一个 MyLocation 之后添加一个新行。但话又说回来,我不知所措。
    • 它确实插入了一行,它在脚本中只是空的,因为我不知道你想放什么。将 s/\n/\n\n/ 替换为 s/\n/\nyour line here\n/ 以解决此问题。
    • 是的,改变它可以解决问题,但是当我将 -i 放在 sed 前面时,它会使用新输出修改整个文件,而不是对我们处理的文本进行内联修改。我的意思是该文件只包含输出而不是带有修改文本的原始文件。
    • 我认为隔离它是要求之一。无论如何,要以其他方式执行此操作,请从 sed 调用中删除 -n 选项,并从 sed 代码末尾删除 p 命令。
    • 如果你想就地编辑文件,你仍然需要给 sed -i 选项;也不要通过-n-n 在代码完成运行后抑制模式空间的自动打印,这在我尝试隔离范围时很好,但当您还想打印文件的其余部分时就不好了。
    【解决方案2】:

    简单的解决方案是使用range

    awk '/<MY_TEXT="XYZ"/,/\\MY_TEXT/' file
    <MY_TEXT="XYZ" PATH="MNO"       #First occurrence of MY_TEXT
    <location= "XYZ" path="ABC"
    \location>
    <R_DATA = MNOP
    <Mylocation ="ghdf" stime=20150301 etime=20150401 >
    <Mylocation ="ghdf" stime=20150401 etime=20150501 >
    \R_DATA>
    <Blah>
    \MY_TEXT>                       #Second occurrence of MY_TEXT
    

    sed

    sed -n '/<MY_TEXT="XYZ"/,/\\MY_TEXT/p' file
    <MY_TEXT="XYZ" PATH="MNO"       #First occurrence of MY_TEXT
    <location= "XYZ" path="ABC"
    \location>
    <R_DATA = MNOP
    <Mylocation ="ghdf" stime=20150301 etime=20150401 >
    <Mylocation ="ghdf" stime=20150401 etime=20150501 >
    \R_DATA>
    <Blah>
    \MY_TEXT>                       #Second occurrence of MY_TEXT
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-13
      • 2013-05-14
      • 2016-10-27
      • 2018-12-07
      • 2018-11-02
      相关资源
      最近更新 更多