用于替换花括号内的数据的sed命令

时间:2017-10-10 05:46:05

标签: regex bash sed

我有一个包含以下数据的文件:

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 \{\}

我还在学习我的正则表达式,任何帮助都会很棒。谢谢!

编辑:另一种选择是仅替换大括号之间的文本

4 个答案:

答案 0 :(得分:2)

使用awk(推荐)

这可以用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)。

使用sed

让我们将替换字符串定义为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)中读取并转回标签aba)。如果我们没有分支回来,我们用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/}

  1. 我们首先定义分支标签:t;
  2. 然后我们告诉sed将下一行追加到当前行N
  3. bt将分支回标签t,并执行N命令。
  4. 如果找到},则bt不会跳回来。
  5. 然后替换语句s/.*/your_replacement_string/将会到达。

答案 3 :(得分:0)

默认情况下,sed命令一次只能处理一行。为了让他们处理一组连续的行,你必须在它们前面加上两个地址(并非所有sed命令都接受两个地址)。

地址可以是数字(行号),$(输入中的最后一行)或分隔的正则表达式。具有两个地址的命令行选择包含范围。此范围从与第一个地址匹配的第一个模式空间开始。范围的结尾是下一个与第二个地址匹配的模式空间。

理论上,让我们写一个sed命令:

sed -i -e "/^upstream fibonacci/,/}/c\\
$2" testfile.sh

是的,该命令跨越两行,不会被错误包装或为了便于阅读。

使用的sed commandc,它期望替换字符串从下一行开始。 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命令的文本。