我有一个包含以下数据的文件:
upstream fibonacci { # restservers
server 10.128.0.3; # 0
server 10.128.0.5; # 1
server 10.128.0.7; # 2
server 10.128.0.8; # 3
server 10.128.0.10; # 4
}
我正在尝试找出一个sed命令来搜索整个块,并将其替换为字符串。
我目前有:
sed -i -e "s/upstream[:space:]fibonacci[:space:]\{.*\}/$2/g" testfile.sh
($ 2是传递给此bash脚本的字符串参数)
这是我的错误
sed: -e expression #1, char 46: Invalid content of \{\}
我还在学习我的正则表达式,任何帮助都会很棒。谢谢!
编辑:另一种选择是仅替换大括号之间的文本
答案 0 :(得分:2)
这可以用sed完成,但awk是更好的选择。
除此之外,"s/something/$2/"
之类的sed命令非常危险,除非$2
的所有内容都清除了所有sed-active字符。
我们来看看这个样本文件:
$ cat file
before...
upstream fibonacci { # restservers
server 10.128.0.3; # 0
server 10.128.0.5; # 1
server 10.128.0.7; # 2
server 10.128.0.8; # 3
server 10.128.0.10; # 4
}
after...
使用awk进行替换:
$ awk -v x="Replacement" '/upstream[[:space:]]+fibonacci[[:space:]]+\{/{f=1} !f{print} /}/{print x; f=0}' file
before...
Replacement
after...
工作原理:
-v x="Replacement"
这将为awk变量x
指定一个字符串。请注意,使用x="$2"
是安全的,因为x
包含awk-active字符无关紧要。
/upstream[[:space:]]+fibonacci[[:space:]]+\{/{f=1}
每当遇到我们的起始行时,将变量f
设置为1(真)
!f{print}
如果f
不成立,请打印当前行。
/}/{print x; f=0}
如果当前行包含}
,则打印x
并将f
设置为零(false)。
让我们将替换字符串定义为shell变量r
:
$ r="Replacement"
这是一个用于替换的sed命令:
$ sed -E ":a; /upstream[[:space:]]+fibonacci[[:space:]]+\{/{ /}/!{N;ba}; s/.*/$r/ }" file
before...
Replacement
after...
工作原理:
:a
这定义了标签a
。
/upstream[[:space:]]+fibonacci[[:space:]]+\{/
这匹配起始字符串。对于匹配的行,将执行以下命令:
/}/!{N;ba}; s/.*/$r/
如果该行包含}
,那么我们会在下一行(N
)中读取并转回标签a
(ba
)。如果我们没有分支回来,我们用shell变量r
的值替换所有模式空间。
如果您愿意,$r
当然可以替换为$2
:
sed -E ":a; /upstream[[:space:]]+fibonacci[[:space:]]+\{/{ /}/!{N;ba}; s/.*/$2/ }" file
请注意,如果$r
(或$2
)包含sed-active字符,则可能会发生意外情况。例如,特制的值可能会导致代码写入文件系统。如果您不确定此变量是否安全,请改用awk代码。
答案 1 :(得分:0)
sed不适合多线比赛。我会改用perl。
use strict;
my $str = 'upstream fibonacci { # restservers
server 10.128.0.3; # 0
server 10.128.0.5; # 1
server 10.128.0.7; # 2
server 10.128.0.8; # 3
server 10.128.0.10; # 4
}';
my $regex = qr/^upstream\sfibonacci\s{.*}$/msp;
my $subst = '$2';
my $result = $str =~ s/$regex/$subst/rg;
print "The result of the substitution is' $result\n";
对于in-place multi-line regex replace(带备份),您可以运行以下行:
perl -0777 -i.bak -pe "s/\nupstream\sfibonacci\s{.*}\s*\n/abc/smg" test.txt
答案 2 :(得分:0)
sed解决方案可能是:
sed -i '/upstream[[:space:]]fibonacci[[:space:]]{/{:t;N;/}/!bt;s/.*/your_replacement_string/}' your_file_name
/upstream[[:space:]]fibonacci[[:space:]]{/
只有upstream fibonacci {
被发现才能执行下一个命令
{/{:t;N;/}/!bt;s/.*/your_replacement_string/}
:t
; sed
将下一行追加到当前行N
bt
将分支回标签t
,并执行N
命令。}
,则bt
不会跳回来。s/.*/your_replacement_string/
将会到达。答案 3 :(得分:0)
默认情况下,sed
命令一次只能处理一行。为了让他们处理一组连续的行,你必须在它们前面加上两个地址(并非所有sed
命令都接受两个地址)。
地址可以是数字(行号),$
(输入中的最后一行)或分隔的正则表达式。具有两个地址的命令行选择包含范围。此范围从与第一个地址匹配的第一个模式空间开始。范围的结尾是下一个与第二个地址匹配的模式空间。
理论上,让我们写一个sed
命令:
sed -i -e "/^upstream fibonacci/,/}/c\\
$2" testfile.sh
是的,该命令跨越两行,不会被错误包装或为了便于阅读。
使用的sed
command是c
,它期望替换字符串从下一行开始。 sed
表达式以$2
之后的引号结尾。
如果你的shell是bash
,那么你可以使用$'\n'
在命令中插入一个新行:
sed -i -e "/^upstream fibonacci/,/}/c\ "$'\n'"$2" testfile.sh
工作原理
sed
命令为c
。其文档解释说:
c \ text
将所选行替换为
text
,其中每个嵌入的换行符都以反斜杠开头。
前面有两个正则表达式地址:/^upstream fibonacci/
是范围的开头,/}/
是范围的结尾。每个范围都以一行以upstream fibonacci
开头,以包含结束括号(}
)的起始行之后的第一行结束。
整个范围将替换为作为参数传递给c
命令的文本。