如何在sed替代的LHS和RHS中使用变量?


60

我想要做:

cat update_via_sed.sh | sed 's/old_name/new_name/' > new_update_via_sed.sh

在我的程序中。

但是我想使用变量,例如

old_run='old_name_952'
new_run='old_name_953'

我试过使用它们,但是替换不会发生(没有错误)。我努力了:

cat update_via_sed.sh | sed 's/old_run/new_run/'
cat update_via_sed.sh | sed 's/$old_run/$new_run/'
cat update_via_sed.sh | sed 's/${old_run}/${new_run}/'

2
您可以在使用命令参数中的参数中找到答案。
manatwork 2013年

Answers:


44

您可以这样做:

sed "s/$old_run/$new_run/" < infile > outfile

但要注意,这$old_run将被视为正则表达式,因此该变量包含的任何特殊字符(例如/.将必须被转义)。类似地,在$new_run中的&\字符将需要特殊对待,而您必须在其中转义/和和换行符。

如果内容$old_run或者$new_run是不是你的控制之下,那么它的关键执行逃逸,否则该代码相当于代码注入漏洞


3
我在sed参数中使用了单引号,将其切换为双引号,并且可以工作。太棒了
Aakash

不是只有sed一个人不会使用正则表达式,而是sed -E吗?
Kiwy,

@Kiwy,不。-e是指定一个sed ë XPRESSION,这样就可以通过一个以上的(如在sed -e exp1 -e exp2)或文件和表达式的组合(sed -f file -e exp)。-E告诉sed使用ERE而不是BRE,您可能会对某些实现感到困惑。
斯特凡Chazelas

我输错了,但可以,这可以解释为什么我在没有sed的情况下使用sed有很多问题,而-E我只掌握扩展的正则表达式而不是常规的regex。感谢您的解释。
Kiwy

@Kiwy,另请参见链接的问答,以获取某些sed实现支持的更多选项,以获取更多正则表达式语法。
斯特凡Chazelas

31

这工作:

cat update_via_sed.sh | sed 's/'"$old_run"'/'"$new_run"'/'

当我想“重用”同一文件时,我实际上将其用于任何希望采用类似方法的人:

cat update_via_sed.sh | sed 's/'"$old_run"'/'"$new_run"'/' > new_update; mv -f new_update update_via_sed.sh

上面创建的新文件然后删除当前文件,而不是将新文件重命名为当前文件。


4
除非不需要特殊字符,否则不需要cat,mv或多余的''。就是这样sed -i s/"$old"/"$new"/ update_via_sed.sh。但是请注意,这对于旧值和新值均无效。例如,它不能包含/等。因为$ old仍然是一个搜索,而$ new是一个替换模式,其中某些字符具有特殊含义。
弗罗斯特斯

1
sed -i "s/$old/$new/"也可以(使用上述预防措施)。sed通常将分隔符视为s命令后的第一个字符-即,如果变量包含斜杠/但不能在(@)处说,则可以使用“ s @ $ old @ $ new @”。
彼得

22

您可以在sed中使用变量,只要它在双引号(而不是单引号)中即可:

sed "s/$var/r_str/g" file_name >new_file

如果/变量中有正斜杠(),请使用其他分隔符,如下所示

sed "s|$var|r_str|g" file_name >new_file

1
+1表示需要使用双引号。那是我的问题。
speckledcarp

1
正是我一直在寻找的,包括使用|在我的情况下,该变量包含路径所以它有/
yorch

因为某些原因管|工作对我来说在MacOS 10.14,但其他的分隔符喜欢@#不。我的环境变量中也有正斜杠。
davidenke '18 -10-22

21

答案是就地“ sed”(使用-i标志)。多亏了彼得。

sed -i "s@$old@$new@" file

2
您在错误的地方引号。引号必须在变量周围,而不是s@(无论如何都不是外壳专用的)。最好是将所有内容都放在引号之内sed -i "s@$old@$new@" file。请注意,这-i不是标准sed选项。
斯特凡Chazelas

我如何$在此命令中转义。就像,我将$xxx整体改变一个变量的值$JAVA_HOME。我尝试过sed -i "s@\$xxx@$JAVA_HOME@" file,但错误提示no previous regular expression
hakunami 2014年

3

man bash 提供有关单引号的信息

将字符括在单引号中可保留引号内每个字符的字面值。即使在单引号之前加反斜杠,也不能在单引号之间引起单引号。

不管你在命令行上输入时,bash解释它,然后将其结果发送到它应该to.In这种情况下被发送,如果使用该程序sed 's/$old_run/$new_run/'时,bash首先看到sed,它识别为可执行存在的$PATH可变。该sed可执行文件要求的输入。Bash查找输入并找到's/$old_run/$new_run/'。单引号表示bash不能解释其中的内容并按原样传递它们。因此,bash然后将它们传递给sed。Sed给出错误,因为$它只能在行尾出现。

相反,如果我们使用双引号(即)"s/$old_run/$new_run/",则bash会看到此并将其解释$old_run为变量名并进行替换(此阶段称为变量扩展)。这确实是我们所需要的。

但是,您必须小心使用双引号,因为双引号首先由bash解释,然后再赋予sed。因此,某些符号(如`)在使用前必须转义。


1

有被轻描淡写的风险-您是否考虑过perl

除其他事项外,它非常擅长于“ sed风格”操作,而且还具有功能更全的编程功能。

看起来像你的榜样,你会真正试图做的是增加了许多。

那么如何:

#!/usr/bin/env perl
use strict;
use warnings 'all'; 

while ( <DATA> ) {
    s/old_name_(\d+)/"old_name_".($1+1)/e;
    print;
}

__DATA__
old_name_932

或作为一种衬板-sed样式:

perl -pe 's/old_name_(\d+)/"old_name_".($1+1)/e'

1
$ echo $d1 | sed -i 's/zkserver1/'${d1}'/g' deva_file
sed: -e expression #1, char 26: unterminated `s' command 

$d1我存储价值

我无法替换变量中的值,因此尝试了以下命令

echo $d1 | sed -i 's/zkserver1/'"${d1}"'/g' deva_file

缺少中的双引号"${d1}",这是错误


-2

假设$old_run$new_run已设置:

cat update_via_sed.sh | eval $(print "sed 's/$old_run/$new_run/g'")

这将在屏幕上显示更改。您可以根据需要将输出重定向到文件。


-2

要在sed中使用变量,请使用双引号“”将变量括在您使用的模式中。例如:a =“ Hi”如果要将变量'a'附加到模式,则可以使用以下命令:sed -n“ 1,/ pattern” $ {a}“ pattern / p” filename


2
$a此处的扩展未引用,这意味着其值中的任何空格都会在shell中调用单词拆分。
库沙兰南达

-2

您还可以使用Perl:

perl -pi -e ""s/$val1/$val2/g"" file

考虑变量值中可能有空格的变量。Perl表达式("")周围的空字符串不会执行任何操作。
库沙兰丹

-2

破弦

不好=> linux看到一个字符串$ old_run:

sed 's/$old_run/$new_run/'

好=> Linux看到一个变量$ old_run:

sed 's/'$old_run'/'$new_run'/'

1
如果$old_run还是$new_run包含空格?
库萨兰达
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.