我正在尝试查看传递给我的程序的变量(变量是1美元)并用所述特殊字符的引用形式替换任何特殊字符,以便没有特殊字符实际上做它通常会做的事情
我的代码是
#!/bin/sh
target="$1"
newtarget=`echo "$target" | sed -e s/\*/\\*/g`
newtarget=`echo "$newtarget" | sed -e s/\^/\\^/g`
newtarget=`echo "$newtarget" | sed -e s/\+/\\+/g`
newtarget=`echo "$newtarget" | sed -e s/\-/\\-/g`
newtarget=`echo "$newtarget" | sed -e s/\\/\\\/g`
newtarget=`echo "$newtarget" | sed -e s/\./\\./g`
newtarget=`echo "$newtarget" | sed -e s/\$/\\$/g`
newtarget=`echo "$newtarget" | sed -e s/\[/\\[/g`
newtarget=`echo "$newtarget" | sed -e s/\]/\\]/g`
sed s/"$newtarget"/"$2"/g "$3" > "$3.updated"
mv "$3.updated" $3
我的第一行,带有$ target,应该查看目标字符串,看看字符串中是否有*。如果有,它将用*替换它。在代码中,它显示为*然后是\ *,是因为程序没有看到*并且认为它想要实际使用*,它只是通过引用*将*视为常规字符。我在所有其他行中都做了同样的事情,但是使用了不同的字符。在第一个之后,它应该检查newtarget并执行相同的操作,但具有不同的字符。
我的整体程序应该做的是,它传递了3个参数,第一个是要替换的字符串,第二个是替换它的字符串,第三个是文件名。所以到最后,如果文件最初是像
那样aa\^a*aa$aa[aaa$a]a
我提供
"a\^a*" "test"
作为参数,结果应为
atestaa$aa[aaa$a]a
但是我的代码仍然不起作用。我的代码出了什么问题?我不知道我的sed语法是否正确编码,或者我的附加语句是否不起作用,或者我是否需要特殊引用一些特殊字符。
编辑:我知道我应该能够像我一样使用多个sed命令来做这个,但我不知道他们为什么不能正常工作,所以我很确定这与我的引用有关在“newtarget =”行末尾的实际sed命令中。EDIT2:我现在在我的代码中引用了我的sed参数,但它仍然无法正常工作。我需要特殊的方式来引用某些特殊字符吗?我假设在每个角色前加一个反斜杠就可以正确引用它。
#!/bin/sh
target="$1"
newtarget=`echo "$target" | sed -e 's/\*/\\*/g'`
newtarget=`echo "$newtarget" | sed -e 's/\^/\\^/g'`
newtarget=`echo "$newtarget" | sed -e 's/\+/\\+/g'`
newtarget=`echo "$newtarget" | sed -e 's/\-/\\-/g'`
newtarget=`echo "$newtarget" | sed -e 's/\\/\\\/g'`
newtarget=`echo "$newtarget" | sed -e 's/\./\\./g'`
newtarget=`echo "$newtarget" | sed -e 's/\$/\\$/g'`
newtarget=`echo "$newtarget" | sed -e 's/\[/\\[/g'`
newtarget=`echo "$newtarget" | sed -e 's/\]/\\]/g'`
sed s/"$newtarget"/"$2"/g "$3" > "$3.updated"
mv "$3.updated" $3
答案 0 :(得分:3)
sed
的多次调用的目的是在每次出现一组字符之前放置一个文字后挡板。这可以通过一次调用sed
来完成,但您需要注意如何指定集合。
首先,让我们看看一般命令的样子:
newtarget=$( echo "$target" | sed -e 's/\([...]\)/\\\1/g'
其中...
将替换为要转义的字符集。此命令使用括号捕获其中一个字符的单个实例,将其替换为后挡板,后跟捕获的字符。要指定字符集,请使用
[]*^+\.$[-]
两个注意事项:首先,]
必须先出现,以免被误认为是集合的结尾,因为[]
是无效的集合。其次,-
必须是最后一个,因此它不会被误认为是范围运算符(例如,[a-z]
是一组小写字母,但[az-]
只是三个字符{{ 1}},a
和z
)。
全部放在一起:
-
答案 1 :(得分:2)
您所做的问题是您没有引用sed
表达式。例如,写
sed s/\*/\\*/
或
sed 's/\*/\\*/'
或
sed s/\*/\\\\*/
我不确定为什么你需要那个复杂的功能来逃避特殊字符。您可以定义一个函数来返回转义的输入字符串:
myescape() { printf "%q" "$1"; }
%q
导致
printf
以格式输出相应的参数 可以重用为shell输入。
将参数传递给sed
的另一个函数:
myreplace() { sed "s/$1/$2/" <<< "$3"; }
现在你可以通过说:
来调用它myreplace "$(myescape 'pattern')" "replacement" "original_string"
示例:
$ myescape() { printf "%q" "$1"; }
$ myreplace() { sed "s/$1/$2/" <<< "$3"; }
$ myreplace $(myescape 'a\^a*') 'test' 'aa\^a*aa[aaa]a'
atestaa[aaa]a