2

我正在尝试使用 sed 在 unix shell (bash) 上的字符串中转义 ('\') 分号 (';')。当我直接执行而不将值分配给变量时,它就可以工作。那是,

$ echo "hello;" | sed 's/\([^\\]\);/\1\\;/g'
hello\;
$

但是,将上述命令分配给变量时,它似乎不起作用:

$ result=`echo "hello;" | sed 's/\([^\\]\);/\1\\;/g'`
$ 
$ echo $result
hello; 
$

知道为什么吗?

我尝试使用带引号和不带引号的值,但这没有帮助。任何线索都非常感谢。

顺便说一句,我首先认为字符串末尾的分号在某种程度上充当了终止符,因此 shell 没有继续执行sed(如果这有任何意义的话)。但是,这似乎不是问题。我尝试使用不在字符串末尾的分号(介于两者之间)。我仍然看到与以前相同的结果。那是,

$ echo "hel;lo" | sed 's/\([^\\]\);/\1\\;/g'
hel\;lo
$
$ result=`echo "hel;lo" | sed 's/\([^\\]\);/\1\\;/g'`
$
$ echo $result
hel;lo
$
4

3 回答 3

4

您根本不需要sed(或任何其他正则表达式引擎):

s='hello;'
echo "${s//;/\;}"

这是一个参数扩展,替换;\;.

也就是说——你为什么要这样做?在大多数情况下,您不希望转义字符(即语法)位于标量变量(即数据)中;它们仅在您将数据解析为语法(例如使用 eval)时才重要,由于其他原因,这是一个坏主意,最好避免(或以编程方式完成,如 via printf %q)。

于 2013-08-16T14:13:44.577 回答
2

我发现有趣的是,使用反引号会给出一个结果(您的结果),而使用 会$(...)给出另一个结果(想要的结果):

$ echo "hello;" | sed 's/\([^\\]\);/\1\\;/g'
hello\;
$ z1=$(echo "hello;" | sed 's/\([^\\]\);/\1\\;/g')
$ z2=`echo "hello;" | sed 's/\([^\\]\);/\1\\;/g'`
$ printf "%s\n" "$z1" "$z2"
hello\;
hello;
$

如果你需要一个论点来使用现代x=$(...)符号而不是旧x=`...`符号,这可能就是它。shell 对反斜杠进行了额外的一轮反斜杠解释。我可以用我在调试 shell 脚本时使用的一个小程序来演示这一点al(用于“参数列表”);你可以模拟它printf "%s\n"

$ z2=`echo "hello;" | al sed 's/\([^\\]\);/\1\\;/g'`
$ echo "$z2"
sed
s/\([^\]\);/\1\;/g
$ z1=$(echo "hello;" | al sed 's/\([^\\]\);/\1\\;/g')
$ echo "$z1"
sed
s/\([^\\]\);/\1\\;/g
$ z1=$(echo "hello;" | printf "%s\n" sed 's/\([^\\]\);/\1\\;/g')
$ echo "$z1"
sed
s/\([^\\]\);/\1\\;/g
$ 

如您所见,执行的脚本因sed您使用的是 x=$(...)符号还是x=`...`符号而异。

s/\([^\]\);/\1\;/g            # ``
s/\([^\\]\);/\1\\;/g          # $()

概括

使用$(...);更容易理解。

于 2013-08-16T14:45:20.493 回答
1

您需要使用四个(三个也可以)。我猜是因为它被解释了两次,第一次由命令解释,第二次由 shell 在读取变量内容时解释:

result=`echo "hello;" | sed 's/\([^\\]\);/\1\\\\;/g'`

echo "$result"

产量:

hello\;
于 2013-08-16T12:54:41.703 回答