在两个字符串之间提取文本并对其执行操作

时间:2015-03-21 15:55:16

标签: bash awk sed

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

<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

我的任务是找到一行<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。但没有用。你们可以帮助我,因为我的脚本不是很好。提前谢谢。

2 个答案:

答案 0 :(得分:1)

这对sed来说有点棘手,但我会对它有所了解。

重要说明:这看起来像一个定义明确的文件格式,但我不认识它。看看是否有直接使用这种格式的工具而不是像sed必须的那样将其视为平面文件,这可能是谨慎的做法。这种解决方案很可能比直接文本hackery更短,更容易理解,更强大。

那就是说,你可以用

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>\n作为标记来分隔工作块;这样做是因为我们知道它不会出现在文本的任何其他地方。 \MY_TEXT>首先出现在我们正在处理的块的最后一行中,因此在输入数据中它之后永远不会出现换行符。 (代码可能更清晰,其他内容没有出现在文本中,但我不知道任何更明显的东西)。

代码的工作原理如下:

#!/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.
}

答案 1 :(得分:1)

简单的解决方案是使用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