rat*_*noz 7 sed text-processing
感谢这个链接,我知道如何将包含斜杠的变量作为模式传递给 sed:
sed "s~$var~replace~g" $file. Juste 使用单字节字符代替 /。
多亏了这个其他链接,我还知道如何仅替换文件中第一次出现的模式(而不是在一行中):
sed "0,/$var/s/$var/replacement/" filename
或者
sed 0,/$var/{s/$var/replacement/} filename
但是如果我这样做:(
sed '0,~$var~s~$var~replacement~' filename
或其他任何以 0 开头的,然后没有斜线),我就会得到一个错误:unknown command: '0'。
我怎么能把两者结合起来?也许通过使用 awk 或 perl 或 ... ?
Sté*_*las 10
尽管:
sed "0,\~$var~s~$var~replacement~"
Run Code Online (Sandbox Code Playgroud)
可用于更改正则表达式分隔符,在sed(或任何其他解释器)代码中嵌入变量扩展在一般情况下是非常不明智的做法。
首先,这里的分隔符并不是唯一需要转义的字符。所有正则表达式运算符也需要这样做。
但更重要的是,特别是对于 GNU sed,这是一个命令注入漏洞。如果 的内容$var不在您的控制之下,那就像将任意数据传递给eval.
尝试例如:
$ var='^~s/.*/uname/e;#'
$ echo | sed "0,\~$var~s~$var~replacement~"
Linux
Run Code Online (Sandbox Code Playgroud)
这 uname命令已运行,幸好是一个无害命令……这次。
非 GNUsed实现不能运行任意命令,但可以覆盖任何文件(使用w命令),这实际上同样糟糕。
更正确的方法是在$varfirst 中转义有问题的字符:
NL='
'
case $var in
(*"$NL"*)
echo >&2 "Sorry, can't handle variables with newline characters"
exit 1
esac
escaped_var=$(printf '%s\n' "$var" | sed 's:[][\/.^$*]:\\&:g')
# and then:
sed "0,/$escaped_var/s/$escaped_var/replacement/" < file
Run Code Online (Sandbox Code Playgroud)
另一种方法是使用perl:
var=$var perl -pe 's/\Q$ENV{var}\E/replacement/g && $n++ unless $n' < file
Run Code Online (Sandbox Code Playgroud)
请注意,我们没有扩展$var传递给的代码内部的内容perl(这将是另一个命令注入漏洞),而是让perl扩展其内容作为其正则表达式处理的一部分(\Q...\E这意味着不会对正则表达式运算符进行特殊处理)。
如果$var包含换行符,则可能仅在末尾只有一个时才匹配。或者,可以传递该-0777选项,以便将输入作为单个记录而不是逐行处理。