我有一个包含以下数据的文件。让我们称之为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命令:
可以有许多
<header>.*</header>
线路。但我需要<header>unique_name</header>
。这是一个唯一的标头名称,我会将其作为核心。它在文件中只出现一次,但可以出现在文件中的任何位置。在myfile.txt中搜索出现在
<header>unique_name</header>
之后的<version>.*</version>
,应将其替换为<version>new version number</version>
。
我尝试过使用grep
、sed
、awk
来实现,但我做不到。请告知。
输入和预期输出:
输入文件"myfile.xml":
- 字符串查找=
<header>unique_name</header>
- newversionNUMBER=新版本编号
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>
.........
使用GNU awk进行第三个参数匹配():
$ 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>
.........
您可以使用这样的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
打印每一行,并根据found
和done
中的状态进行版本替换。
类似于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