在文件中搜索一行并用linux中的换行替换下一个模式匹配的行(Shell脚本)

时间:2016-07-23 13:53:31

标签: linux shell awk sed grep

我有一个包含以下数据的文件。请将其称为myfile.xml

.........
<header>unique_name</header>
......
somelines
......
<version>I need only this line</version>
......
......
<version>This is second match of version, which I dont want</version>

现在我正在寻找低于事物的linux命令:

  1. 可以有许多<header>.*</header>行。但是我需要<header>unique_name</header>。这是一个唯一的标题名称,我会用它来核心。它只出现在文件中一次,但可以出现在文件的任何位置。

  2. 搜索myfile.txt中<version>.*</version>之后显示的<header>unique_name</header>,并将其替换为<version>new version number</version>

  3. 我尝试使用grepsedawk进行实施,但我做不到。请指教。

    输入和预期输出:

    输入文件&#34; myfile.xml&#34;:

    • stringtoFIND = <header>unique_name</header>
    • newversionNUMBER = NEW_VERSION_NUMBER

    以下myfile.xml文件内容:

    <header>Some strings</header>
    ......Somelines...........
    <version>I dont need this line, since header doesnt match stringtoFIND variable</version>
    
    <header>unique_name</header>
    .............
    <version>I need only this line</version>
    ...........
    ..........
    <version>I Dont need this line</version>
    .........
    

    预期输出

    <header>Some strings</header>
    ......Somelines...........
    <version>I dont need this line, since header doesnt match stringtoFIND variable</version>
    
    <header>unique_name</header>
    .............
    <version>new_version_number</version>
    ...........
    ..........
    <version>I Dont need this line</version>
    .........
    

3 个答案:

答案 0 :(得分:1)

使用GNU awk为第3个arg匹配():

$ cat tst.awk
match($0,/<header>(.*)<\/header>/,a) {
    inBlock = (a[1] == "unique_name" ? 1 : 0)
}

inBlock && match($0,/(.*<version>).*(<\/version>.*)/,a) {
    $0 = a[1] "new_version_number" a[2]
    inBlock = 0
}

{ print }

$ awk -f tst.awk file
<header>Some strings</header>
......Somelines...........
<version>I dont need this line, since header doesnt match stringtoFIND variable</version>

<header>unique_name</header>
.............
<version>new_version_number</version>
...........
..........
<version>I Dont need this line</version>
.........

答案 1 :(得分:0)

你可以用这样的awk来做到这一点。

<强> script.awk

/<header>unique_name<\/header>/ { found=1; done=0 }
/<version>.*<\/version>/ && found && !done {
      # replace version in $0
      gsub(/<version>.*<\/version>/,"<version>new_version_number</version>")
      done = 1
    }

# implicitly print current $0:
1

运行脚本:awk -f script.awk yourfile > newfile

打印每一行,并根据founddone中的状态更换版本。

答案 2 :(得分:0)

Lars Fischer对答案的类似答案:

#! /usr/bin/awk -f

/<header>.*<\/header>/ {
    looking = 0
}

 /<header>unique_name<\/header>/ {
    looking = 1
}

looking && /<version>.*<\/version>/ {
    n = match($0, /^ *<version>/)
    $0 = substr($0, 1, n) Version "</version>"
    looking = 0    
}

{ print }

我构建新版本行而不是替换它。在规则中,我将布尔值放在正则表达式之前,因为它更有效,而不是你会注意到。我个人不喜欢用1结尾表示打印,但这只是一种风格选择。

调用

$ awk -v Version="$version" -f script.awk input