[英]Replace value in nth line ABOVE search string using awk/sed
I have a large firewall configuration file with sections like these distributed all over:我有一个大型防火墙配置文件,其中分布着这些部分:
edit 78231
set srcintf "port1"
set dstintf "any"
set srcaddr "srcaddr"
set dstaddr "vip-dnat"
set service "service"
set schedule "always"
set logtraffic all
set logtraffic-start enable
set status enable
set action accept
next
I want to replace value "port1"
, which is 3 lines above search string "vip-dnat"
.我想替换值
"port1"
,它位于搜索字符串"vip-dnat"
上方 3 行。
It seems the below solution is close but I don't seem to be able to invert the search to check above the matched string.下面的解决方案似乎很接近,但我似乎无法反转搜索以检查匹配的字符串上方。 Also it does not replace the value inside the file: Replace nth line below the searched pattern in a file
它也不会替换文件内的值: Replace nth line below the searched pattern in a file
I'm able to extract the exact value using the following awk command but simply cannot figure out how to replace it within the file ( sub
/ gsub
?):我可以使用以下 awk 命令提取确切的值,但根本无法弄清楚如何在文件中替换它(
sub
/ gsub
?):
awk -v N=3 -v pattern=".*vip-dnat.*" '{i=(1+(i%N));if (buffer[i]&& $0 ~ pattern) print buffer[i]; buffer[i]=$3;}' filename
"port1"
We could use tac
+ awk
combination here.我们可以在这里使用
tac
+ awk
组合。 I have created a variable occur
with value after how many lines(when "vip-dnat"
is found) you need to perform substitution.我创建了一个变量,在您需要执行替换的行数之后(当找到
"vip-dnat"
时) occur
值。
tac Input_file |
awk -v occur="3" -v new_port="new_port_value" '
/\"vip-dnat\"/{
found=1
print
next
}
found && ++count==occur{
sub(/"port1"/,new_port)
found=""
}
1' |
tac
Explanation: Adding detailed explanation for above.说明:为上述添加详细说明。
tac Input_file | ##Printing Input_file content in reverse order, sending output to awk command as an input.
awk -v occur="3" -v new_port="new_port_value" ' ##Starting awk program with 2 variables occur which has number of lines after we need to perform substitution and new_port what is new_port value we need to keep.
/\"vip-dnat\"/{ ##Checking if line has "vip-dnat" then do following.
found=1 ##Setting found to 1 here.
print ##Printing current line here.
next ##next will skip all statements from here.
}
found && ++count==occur{ ##Checking if found is SET and count value equals to occur.
sub(/"port1"/,new_port) ##Then substitute "port1" with new_port value here.
found="" ##Nullify found here.
}
1' | ##Mentioning 1 will print current line and will send output to tac here.
tac ##Again using tac will print output in actual order.
Use a Perl one-liner.使用 Perl 单线。 In this example, it changes line number 3 above the matched string to
set foo bar
:在此示例中,它将匹配字符串上方的第 3 行更改为
set foo bar
:
perl -0777 -pe 's{ (.*\n) (.*\n) ( (?:.*\n){2} .* vip-dnat ) }{${1} set foo bar\n${3}}xms' in_file
Prints:印刷:
edit 78231
set foo bar
set dstintf "any"
set srcaddr "srcaddr"
set dstaddr "vip-dnat"
set service "service"
set schedule "always"
set logtraffic all
set logtraffic-start enable
set status enable
set action accept
next
When you are satisfied with the replacement written into STDOUT, change perl
to perl -i.bak
to replace the file in-place.当您对写入 STDOUT 的替换感到满意时,将
perl
更改为perl -i.bak
以就地替换文件。
The Perl one-liner uses these command line flags: Perl 单行代码使用这些命令行标志:
-e
: Tells Perl to look for code in-line, instead of in a file. -e
:告诉 Perl 查找内联代码,而不是在文件中。
-p
: Loop over the input one line at a time, assigning it to $_
by default. -p
:一次循环输入一行,默认将其分配给$_
。 Add print $_
after each loop iteration.在每次循环迭代后添加
print $_
。
-i.bak
: Edit input files in-place (overwrite the input file). -i.bak
:就地编辑输入文件(覆盖输入文件)。 Before overwriting, save a backup copy of the original file by appending to its name the extension .bak
.在覆盖之前,通过在其名称后附加扩展名
.bak
来保存原始文件的备份副本。 -0777
: Slurp files whole. -0777
: 整个 Slurp 文件。
(.*\n)
: Any character, repeated 0 or more times, ending with a newline. (.*\n)
:任何字符,重复 0 次或多次,以换行符结尾。 Parenthesis serve to capture the matched part into "match variables", numbered $1
, $2
, etc, from left to right according to the position of the opening parenthesis.括号用于将匹配的部分捕获为“匹配变量”,根据左括号的 position 从左到右编号为
$1
、 $2
等。
( (?:.*\n){2}.* vip-dnat )
: 2 lines followed by the line with the desired string vip-dnat
. ( (?:.*\n){2}.* vip-dnat )
: 2 行,后跟所需字符串vip-dnat
的行。 (?: ... )
represents non-capturing parentheses. (?: ... )
表示非捕获括号。
SEE ALSO:也可以看看:
perldoc perlrun
: how to execute the Perl interpreter: command line switchesperldoc perlrun
:如何执行 Perl 解释器:命令行开关perldoc perlre
: Perl regular expressions (regexes) perldoc perlre
: Perl 正则表达式(正则表达式)
perldoc perlre
: Perl regular expressions (regexes): Quantifiers; perldoc perlre
: Perl 正则表达式(正则表达式):量词; Character Classes and other Special Escapes;字符类和其他特殊转义; Assertions;
断言; Capture groups
捕获组
perldoc perlrequick
: Perl regular expressions quick start perldoc perlrequick
: Perl 正则表达式快速入门
The regex uses these modifiers:正则表达式使用这些修饰符:
/x
: Ignore whitespace and comments, for readability. /x
:为了可读性,忽略空格和注释。
/m
: Allow multiline matches. /m
:允许多行匹配。
/s
: Allow .
/s
:允许.
to match a newline.匹配换行符。
Whenever you have tag-value pairs in your data it's best to first create an array of that mapping ( tag2val[]
below) and then you can test and/or change and/or print the values in whatever order you like just be using their names:每当您的数据中有标签值对时,最好先创建一个该映射的数组(下面的
tag2val[]
),然后您可以按照您喜欢的任何顺序测试和/或更改和/或打印值,只是使用它们名称:
$ cat tst.awk
$1 == "edit" { editId=$2; next }
editId != "" {
if ($1 == "next") {
# Here is where you test and/or set the values of whatever tags
# you like by referencing their names.
if ( tag2val[ifTag] == ifVal ) {
tag2val[thenTag] = thenVal
}
print "edit", editId
for (tagNr=1; tagNr<=numTags; tagNr++) {
tag = tags[tagNr]
val = tag2val[tag]
print " set", tag, val
}
print $1
editId = ""
numTags = 0
delete tag2val
}
else {
tag = $2
sub(/^[[:space:]]*([^[:space:]]+[[:space:]]+){2}/,"")
sub(/[[:space:]]+$/,"")
val = $0
if ( !(tag in tag2val) ) {
tags[++numTags] = tag
}
tag2val[tag] = val
}
}
$ awk -v ifTag='dstaddr' -v ifVal='"vip-dnat"' -v thenTag='srcintf' -v thenVal='"foobar"' -f tst.awk file
edit 78231
set srcintf "foobar"
set dstintf "any"
set srcaddr "srcaddr"
set dstaddr "vip-dnat"
set service "service"
set schedule "always"
set logtraffic all
set logtraffic-start enable
set status enable
set action accept
next
Note that the above approach:注意上面的方法:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.