Bash sed:替换所有特殊字符(无效范围结束)

时间:2017-03-03 20:54:31

标签: bash sed

最终目标是在文件中替换包含密码的行(可以包含任何字符):

...
passw=old#$#$@$#@%{}[]
...

我有替换字符串变量: (别介意现在的双引号)

$old="passw=old#$#$@$#@%{}[]"

$new="passw=new#$#$@$#@%{}[]"

如果我使用简单的sed -i "s#$old#$new#g" file.txt",它显然无法正常工作,因为特殊字符会破坏语法。

要使其正常工作,我需要使用\转义所有特殊字符,例如:\[

我尝试使用这样的东西:

esc=$("$old" | sed 's/[][`~!@#$%^&*()-_=+{}\|;:",<.>/?'"'"']/\\&/g'

然而,它给了我以下错误:

sed: -e expression #1, char42: Invalid range end

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:2)

awk救援!

请注意,替换基于正则表达式,awk中的搜索字符串需要转义特殊字符,sed中的搜索和替换字符串都需要转义。这需要预处理字符串。或者,如果输入文件是结构化的,则可以尝试字符串相等性检查

例如,

$ awk -v old='old#$#$@$#@%{}[]'    \
      -v new='[]{}new#$#$@$#@%'    \
      -v key='passw=' '"^"key{line=$0; 
                              sub(key,"",line); 
                              if(line==old) $0=key new}1' file 

在输入文件上运行

passw=old#$#$@$#@%{}[]
some other line with old#$#$@$#@%{}[]

将生成

pasw=[]{}new#$#$@$#@%
some other line with old#$#$@$#@%{}[]

您还可以对完整的key=value匹配进行相等检查,如下所示

$ awk -v old='old#$#$@$#@%{}[]' \
      -v new='[]{}new#$#$@$#@%' \
      -v key='passw=' '$0==key old{$0=key new}1' file

或通过搜索和替换字符串进一步简化包括key=前缀

awk -v old='passw=old#$#$@$#@%{}[]' \
    -v new='passw=[]{}new#$#$@$#@%' \
          '$0==old{$0=new}1' file

这些假设您的密码记录在一个单独的行上。如果它不是一个有效的假设,您可以将RS和ORS设置为' '并删除输出文件的最后一个字符(添加的最后一个ORS)。另一个解决方案可能是迭代循环中的字段(例如for(i=1;i<=NF;i++) if($i==old) $i=new...

答案 1 :(得分:1)

如果没有适当的逃避,你将无法实现它。我尝试了sed,perl等,但所有这些都破了,特别是在chars {}和[]中。

你可以同时使用sed来逃避所有非常规字符 在下面的例子中,我逃避了不是文本的所有内容(a-z和A-Z)而不是数字(0-9)

$ cat file14
passw=old#$#$@$#@%{}[]

$ old='passw=old#$#$@$#@%{}[]' && echo "$old"  #mind the single quotes.
passw=old#$#$@$#@%{}[]

$ new='passw=new$#$#$$0-.?!@#$%^&*()_+@$#@%[]{}' && echo "$new"
passw=new$#$#$$0-.?!@#$%^&*()_+@$#@%[]{}

$ old=$(sed 's/[^a-zA-Z0-9]/\\&/g' <<<"$old") && echo "$old"
passw\=old\#\$\#\$\@\$\#\@\%\{\}\[\]

$ new=$(sed 's/[^a-zA-Z0-9]/\\&/g' <<<"$new") && echo "$new"
passw\=new\$\#\$\#\$\$0\-\.\?\!\@\#\$\%\^\&\*\(\)\_\+\@\$\#\@\%\[\]\{\}

$ sed -r "s/$old/$new/" file14
passw=new$#$#$$0-.?!@#$%^&*()_+@$#@%[]{}