Unix 用sed引用特殊字符

Unix 用sed引用特殊字符,unix,sed,Unix,Sed,我试图查找一个传递给我的程序的变量,变量是$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` newtarge

我试图查找一个传递给我的程序的变量,变量是$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

你所做的事情的问题是你没有引用你的sed表达式。例如,写

sed s/\*/\\*/
或者作为

sed 's/\*/\\*/'

我不知道为什么你需要那个复杂的函数来逃避特殊的角色。您可以定义一个返回转义输入字符串的函数:

myescape() { printf "%q" "$1"; }
%q

使printf以以下格式输出相应的参数: 可以作为shell输入重用

将参数传递给sed的另一个函数:

例如:

$ myescape() { printf "%q" "$1"; }
$ myreplace() { sed "s/$1/$2/" <<< "$3"; }
$ myreplace $(myescape 'a\^a*') 'test' 'aa\^a*aa[aaa]a'
atestaa[aaa]a

你所做的事情的问题是你没有引用你的sed表达式。例如,写

sed s/\*/\\*/
或者作为

sed 's/\*/\\*/'

我不知道为什么你需要那个复杂的函数来逃避特殊的角色。您可以定义一个返回转义输入字符串的函数:

myescape() { printf "%q" "$1"; }
%q

使printf以以下格式输出相应的参数: 可以作为shell输入重用

将参数传递给sed的另一个函数:

例如:

$ myescape() { printf "%q" "$1"; }
$ myreplace() { sed "s/$1/$2/" <<< "$3"; }
$ myreplace $(myescape 'a\^a*') 'test' 'aa\^a*aa[aaa]a'
atestaa[aaa]a

多次调用sed的目的是在一组字符的每次出现之前放置一个文字反斜杠。这可以通过对sed的一次调用来完成,但是您需要注意如何指定集合

首先,让我们看看通用命令是什么样子的:

newtarget=$( echo "$target" | sed -e 's/\([...]\)/\\\1/g'
在哪里。。。将替换为要转义的字符集。此命令使用括号捕获其中一个字符的单个实例,将其替换为后跟捕获字符的反斜杠。要指定字符集,请使用

[]*^+\.$[-]
注意:首先,]必须放在第一位,以免误认为是集合的结尾,因为[]是无效集合。其次,-必须排在最后,以免误认为是范围运算符,例如,[a-z]是一组小写字母,而[az-]只是三个字符a、z和-

总而言之:

 newtarget=$( echo "$target" | sed -e 's/\([]*^+\.$[-]\)/\\\1/g' )

多次调用sed的目的是在一组字符的每次出现之前放置一个文字反斜杠。这可以通过对sed的一次调用来完成,但是您需要注意如何指定集合

首先,让我们看看通用命令是什么样子的:

newtarget=$( echo "$target" | sed -e 's/\([...]\)/\\\1/g'
在哪里。。。将替换为要转义的字符集。此命令使用括号捕获其中一个字符的单个实例,将其替换为后跟捕获字符的反斜杠。要指定字符集,请使用

[]*^+\.$[-]
注意:首先,]必须放在第一位,以免误认为是集合的结尾,因为[]是无效集合。其次,-必须排在最后,以免误认为是范围运算符,例如,[a-z]是一组小写字母,而[az-]只是三个字符a、z和-

总而言之:

 newtarget=$( echo "$target" | sed -e 's/\([]*^+\.$[-]\)/\\\1/g' )

引用sed-e的论点。顺便说一下,您也可以将它们折叠为一个:sed=e的/\*/\\&/g'-e的/\^/\\&/g'…甚至sed-e的/[][*^+\.$-]/\&/g'。您还需要转义斜杠分隔符。我尝试了您给我的最后一段代码,但无法使其正常工作,因此我返回到原始代码,只需

就像你说的那样,我使用sed-e参数,但我仍然得到一个错误。当你说我需要转义斜杠分隔符时,你的意思是在我所有的行中,还是在我有很多斜杠分隔符的行中,sed-e的参数是/\\/\\\\\/g'Quote。顺便说一下,您也可以将它们折叠为一个:sed=e的/\*/\\&/g'-e的/\^/\\&/g'…甚至sed-e的/[][*^+\.$-]/\&/g'。您还需要转义斜杠分隔符。我尝试了您给我的最后一段代码,但无法使其正常工作,因此我返回到原始代码,并像您所说的那样引用了sed-e参数,但仍有一个错误。当你说我需要转义斜杠分隔符时,你的意思是在我所有的行中,还是在我有很多斜杠分隔符的行中,这不是我们应该做的。我应该用sed命令这样做,我想知道为什么我的代码不起作用。@JoJoBya你应该在你的问题中清楚地说明这是家庭作业,你不是在寻找问题的解决方案,而是希望人们修复你的代码。printf%q是GNU bash特有的,他需要转义sed特殊字符,而不是shell特殊字符。@mirabilos如果你跳进去,你很可能会认为OPs代码中的问题是shell本身。@JoJoBya脚本的问题是你没有引用sed表达式。具体的问题还有很多,但我们不应该这样做。我应该用sed命令这样做,我想知道为什么我的代码不起作用。@JoJoBya你应该在你的问题中清楚地说明这是家庭作业,你不是在寻找问题的解决方案,而是希望人们修复你的代码。printf%q是GNU bash特有的,他需要转义sed特殊字符,而不是shell特殊字符。@mirabilos如果你跳进去,你很可能会认为OPs代码中的问题是shell本身。@JoJoBya脚本的问题是你没有引用sed表达式。具体的问题还存在其他问题。我尝试将其实现为newtarget=echo$target | sed-e's/]*^+\.$[-/\\\1/g'``但我得到了一个未终止的's'命令的错误,并且没有以前的正则表达式。我假设您指的是[…]它只是象征着我应该把集合放在那里,而不是我应该把它放在括号里,因为如果我先放一个[],我们会在开头有一个[]。不,周围的[]是必要的,因为它指定了一个正则表达式,与它们包含的字符之一相匹配。请看我关于空集合[]无效的评论,因此首先放置[]允许按字面解释,而不是作为集合的结束括号。嗯,好的。如果我想在场景中加入另一个特殊角色,我会怎么做?例如,如果我想包括`,我会把它放在+和^之间,还是需要一些特殊的东西,比如括号和-?我的命令看起来像newtarget=echo$target | sed-e的/\[]*^+\.$[-]\/\\\1/g'现在,但我得到的错误是无效的反向引用。关于这些角色,我是否有任何特殊要求?此外,在echo中,e前面和g后面的逗号后面都有`注释,但是注释的格式很奇怪。我认为不同版本的sed对什么是转义和什么不是转义有不同的规则。尝试删除括号前的反斜杠,看看是否有帮助。我尝试将其实现为newtarget=echo$target | sed-e's/]*^+\.$[-/\\\1/g'``但我得到了一个错误,即没有终止的's'命令,也没有以前的正则表达式。我假设您指的是[…]它只是象征着我应该把集合放在那里,而不是我应该把它放在括号里,因为如果我先放一个[],我们会在开头有一个[]。不,周围的[]是必要的,因为它指定了一个正则表达式,与它们包含的字符之一相匹配。请看我关于空集合[]无效的评论,因此首先放置[]允许按字面解释,而不是作为集合的结束括号。嗯,好的。如果我想在场景中加入另一个特殊角色,我会怎么做?例如,如果我想包括`,我会把它放在+和^之间,还是需要一些特殊的东西,比如括号和-?我的命令看起来像newtarget=echo$target | sed-e的/\[]*^+\.$[-]\/\\\1/g'现在,但我得到的错误是无效的反向引用。关于这些角色,我是否有任何特殊要求?此外,在echo中,e前面和g后面的逗号后面都有`注释,但是注释的格式很奇怪。我认为不同版本的sed对什么是转义和什么不是转义有不同的规则。尝试删除括号前的反斜杠,看看是否有帮助。