`
xinklabi
  • 浏览: 1586642 次
  • 性别: Icon_minigender_1
  • 来自: 吉林
文章分类
社区版块
存档分类
最新评论

shell历险之——引用的迷途(单引号,双引号,反斜杠)

 
阅读更多

我们知道在shell中有两类字符,一类是普通字符(literal),在shell中没有任何特殊意义;另一类是所谓“元字符”(meta),在shell中有特殊的含义或用法。

当我们需要去掉元字符的特殊含义而恢复其字面意义时就必须使用“引用”(quoting)。通常有三种引用方式,他们是转义(Escape,使用反斜杠字符\,即backslash),强引用(使用单引号',即single quote)和弱引用(使用双引号", 即double quote)。

转义:是用反斜杠放在需要转义的一个字符前,表示那个字符要看作一个普通字符。
强引用:是用单引号把要转义的字符串括起来,其中任何字符都看作普通字符,除了单引号自身。所以你无法在两个单引号之间包含单引号,用\转义也不行。
弱引用:是用双引号把要转义的字符串括起来,除了双引号"本身,其中的大部分字符都看作普通字符。例外的还有\,$,`三个特殊字符。因为\在""中是特殊字符,所以你可以在其中包含"本身,前提是必须转义。$是特殊字符,这表示你可以使用变量$var/${var}及其它,在ksh/bash中可以引用算术表达式的结果$((...)),还可以作命令替换$()。由于`是特殊字符在bsh中也可以作命令替换,但只能使用`...`的语法(这个在ksh/bash中也可以使用)。

关于三种引用,网中人的“shell十三问”之第四问已经讲得很清楚了,我这里就不重复了。

今天我们单独研究一下反斜线\。这是一个有魔力的字符,它可以用来对任何字符转义,也包括它自己。但是在不同的shell实现中它的表现似乎不尽相同,有时结果让你会大吃一惊。

先来看一个简单的例子,假定我们要输出单独一个\,先用bash:

  1. $ echo \\
  2. \
  3. $ echo "\\"
  4. \
  5. $ echo '\'
  6. \
复制代码


第一个echo,因为\是元字符,所以必须对它进行转义,所以我们必须用两个\。
第二个echo,因为""是弱引用,其中的\仍然是特殊字符,所以同样必须转义。
第三个echo,''是强引用,\在单引号之中是普通字符,这样就不用再转义了,所以只用一个\。

OK,假如我们要输出连续两个\,怎样呢?看一下:

  1. $ echo \\\\
  2. \\
  3. $ echo "\\\\"
  4. \\
  5. $ echo '\\'
  6. \\
复制代码


嗯,好像没有什么奇怪的事发生,我们简单地使用双倍的\就搞定了。

那再让我们用ksh来试试来做同样的事:

  1. $ echo \\
  2. \
  3. $ echo "\\"
  4. \
  5. $ echo '\'
  6. \
复制代码


这个容易,简单的重复罢了。再来两个\:

  1. $ echo \\\\
  2. \
  3. $ echo "\\\\"
  4. \
  5. $ echo '\\'
  6. \
复制代码


等等,怎么搞的?为什么只输出了一个\?
再加一个\会如何?

  1. $ echo \\\\\
  2. >
  3. \
  4. $ echo \\\\\\
  5. \\
  6. $ echo "\\\\\"
  7. >
  8. \
  9. $ echo "\\\\\\"
  10. \\
  11. $ echo '\\'
  12. \\
复制代码


第一个echo没有立即执行,ksh给出了一个>(PS2提示符),等待我们继续输入,回车后echo仍然只输出了一个\。
第二个echo后面是六个\,呼~,这回终于输出两个\了。
双引号的情形也是类似,我们仍然需要六个\。
第五个echo,好在单引号的结果还算不错,只要两个\就行了。

你可以继续做这个试验,最后会发现在不用单引号时,我们需要2个或4个\输出1个\,需要6个或8个\输出2个\,10个或12个\来输出3个\,......真是又臭又长!

  1. 输出        命令行需要\的个数
  2. \        2/4
  3. \\       6/8
  4. \\\      10/12
  5. \\\\     14/16
  6. \\\\\   18/20
  7. ...       ...
  8. n个\    4n-2/4n
复制代码


厌倦了吗?其实ksh下除了用',还有其它方法剪断这“懒婆娘的裹脚布”。窍门就在于echo命令的-E选项:

  1. $ echo -E \\
  2. \
  3. $ echo -E \\\\
  4. \\
  5. $ echo -E \\\\\\
  6. \\\
复制代码


很好!这样与bash下的情况就一样了,-E选项是不是很神奇呀!为什么呢?

原来bash和ksh的echo命令缺省的表现是不同的。我们知道echo命令可以接受一些转义字符序列来表示特殊的字符,如\n表示换行,\a表示蜂鸣,\t表示水平制表符等等。显然在解释转义序列时\是一个特殊字符。

在bash下echo缺省的设置是不解释这些转义序列,为了告诉它解释转义序列我们必须使用-e选项。

而在ksh下echo的缺省设置就会解释这些转义序列,我们可以用-E选项让它不解释转义序列。所以ksh下在不使用-E选项时实际上会发生两次转义的过程,第一次发生在ksh处理命令行时,第二次发生在echo命令处理它的参数时。让我们看下面这个简单的例子:

  1. $ set -x
  2. $ echo \\\\
  3. + echo \\
  4. \
复制代码


先用set -x让ksh显示命令行处理的结果,我们看到,第一个\转义第二个\,去掉它的特殊含义,同样第三个\转义第四个\去掉它的特殊含义,这样命令行处理完毕以后传给echo的参数是\\。echo然后将\\解释成了\并输出。于是我们只得到一个\。

bsh中echo的缺省表现与ksh中类似,解释转义序列,不过可惜无法关掉这一功能。我们还是可以使用外部命令来不解释转义序列原样输出,例如在linux下可以用
/bin/echo -E(可以省略)来做。

下来看一个从本论坛来的例子,提问者的意图是将dos格式的路径中的\变成\\,但他的shell好像工作得不好:

  1. $echo C:\\tmp | sed 's/\\/&\\/'
  2. C:        mp
  3. $echo 'C:\abc'|sed 's/\\/\\\\/'
  4. C:bc
复制代码


在看过上面我们对引用和echo的讨论之后,您能为他解释一下其中的原因吗?
对了,这两条命令的语法都没有错,不过提问者使用的shell八成是ksh(也可能是bsh,但可能性较小),问题是出在echo上。在ksh下echo默认解释转义序列,所以命令行的
echo c:\\tmp部分先做命令行解释,\\变成\,于是执行:
echo 'c:\tmp'
而\t是一个转义序列,它代表水平制表符,所以echo最后输出
c:<水平制表符>mp
同样
echo 'c:\abc'
会输出
c:<蜂鸣字符>bc
你应该会听到你的终端发出“嘟”的一声。
这下清楚了吧?echo的输出就是错误的,后面sed的替换根本就没有匹配执行,当然不会有正确的结果。
上面两个命令在bash下是正确的,为什么?
那在ksh下怎样修改让它正确工作呢?如果是bsh呢?改法可能不止一种,不过这个还是留给亲爱的读者您作为一个练习好了。

分享到:
评论

相关推荐

    PHP去掉json字符串中的反斜杠\及去掉双引号前的反斜杠

    例如,双引号前可能会有不必要的反斜杠。这时,就需要额外的处理步骤来修正字符串。通常,可以先将错误的转义字符替换掉,例如将`\"`替换成`"`。 ```php $json = str_replace('\"', '"', $json); ``` 另一个需要...

    linux shell中单引号、双引号、反引号、反斜杠的区别

    在Linux Shell编程中,了解和掌握单引号、双引号、反引号和反斜杠的区别至关重要,因为它们在处理字符串和命令时起到不同的作用。 1. 单引号(' '): 单引号的作用是告诉Shell忽略其内部的所有特殊字符。这意味着...

    shell编程基础 单引号和双引号的区别

    在双引号中,大多数特殊字符会被Shell解析,但美元符号 `$`、反引号 `` ` `` 和反斜杠 `\` 除外。美元符号允许变量替换,反引号用于命令替换,而反斜杠用于转义。例如,如果有一个双引号中的字符串 `"Hello, $var!"`...

    php单引号和双引号的区别

    然而,在**单引号('')**中,除了`\'`(单引号)和`\\`(反斜杠)之外,其他转义序列都不会被解析,这使得单引号字符串处理更简单、更快,但同时也限制了其灵活性。 ### 多行字符串定义 对于多行字符串,PHP提供了...

    php双引号、单引号的区别.zip

    在双引号和单引号字符串中都可以使用反斜杠(\)进行转义。例如,如果你想在字符串中包含一个双引号,你可以写成 `\"`。单引号字符串中,反斜杠主要用于转义单引号自身,如 `\'`。 4. 复杂变量嵌套: 如果要在...

    mysql语句如何插入含单引号或反斜杠的值详解

    在进行MySQL数据库操作时,我们常常需要插入包含特殊字符的数据,其中单引号(')和反斜杠(\)是最常见的特殊字符。它们在SQL语句中具有特殊的意义,如果不加以处理,就会导致语法错误,从而影响数据的插入。本文将...

    给行文本添加单引号例子

    - 转义单引号需要使用反斜杠 `\`,如 `'\''` 会在字符串中插入一个单引号。 5. **文本编辑器和查找替换功能**: - 许多文本编辑器(如Notepad++, Sublime Text等)提供了查找和替换功能,可以方便地批量添加或...

    浅析Js中的单引号与双引号问题

    双引号中再用双引号要这样:var str = “abc\”def\”ghi”用反斜杠来禁止解析双引号。 下面是我摘录的,希望对你有用: 在一个网页中的按钮,写onclick事件的处理代码,不小心写成如下:&lt;input value=”Test” ...

    每天一个Linux命令之shell单引号和双引号的经典解释

    在Linux Shell脚本编程中,理解单引号、双引号和反引号的作用至关重要,因为它们直接影响到命令行参数的解析方式。下面是对这些概念的详细解释。 **单引号**:在Shell中,单引号(' ')的作用是创建一个字符串,...

    解决python 执行sql语句时所传参数含有单引号的问题

    这里注意,转义字符是反斜杠(\),所以要写成`\\'`而不是`\'`,因为Python字符串中,单个反斜杠会被解释为转义字符,所以需要写成双反斜杠来表示一个实际的反斜杠。 此外,描述中还提到了Python动态生成SQL语句和...

    Javascript里的String原来不能用双引号括起来.jpg

    1. **转义字符**:使用反斜杠(`\`)对内部的双引号进行转义。 ```javascript var str = "This is a \"string\" example."; ``` 2. **换用其他类型的引号**:例如,使用单引号定义字符串。 ```javascript var ...

    反斜杠转正斜杠 bat

    平时打代码,加载路径的时候,总是反斜杠,然而路径名需要正斜杠,所以自己写了一个简单的bat,方便转换 效果预览:https://blog.csdn.net/a2583211/article/details/95047176

    Js参数值中含有单引号或双引号问题的解决方法

    在这个例子中,我们使用了`onclick`事件,并在双引号前添加了反斜杠转义,同时保留了单引号的原始形式,这样就可以处理含有双引号的参数值。 但是,这种方法仍然有一些限制。例如,如果参数之间有空格,或者参数值...

    PHP中单引号与双引号的区别分析

    在单引号中,只有两个转义序列会被解析:'\''(单引号自身)和 '\\\'(反斜杠)。这意味着在单引号内,其他转义序列如'\n'(换行)、'\r'(回车)和'\t'(制表符)都不会被解析,它们会被当作普通字符输出。而双引号...

    Android relaceALL替换字符串中的反斜杠

    因此,如果我们要直接替换反斜杠,需要使用两个反斜杠`\\`来表示一个实际的反斜杠字符。 ### 3. 替换字符串中的反斜杠 在`Android`应用中,如果你想要替换字符串中的所有反斜杠,代码可能如下所示: ```java ...

    Shell脚本中的特殊字符(美元符、反斜杠、引号等)作用介绍

    然而,`$`, `\`, ``, 和反引号在双引号中仍然是特殊字符。 - 输出特殊字符的原始形式时,如果使用双引号,如`echo " $"`,`$`将被解析为变量,而不是输出原始字符。因此,需要使用单引号或反斜杠来保持其原形。 5....

    详解json串反转义(消除反斜杠).docx

    ### 详解 JSON 串反转义(消除反斜杠) 在处理 JSON 数据时,经常会遇到一些字符串需要进行反转义的情况,尤其是在从文件中读取 JSON 字符串并希望将其转换为 JSON 对象时。本文将详细介绍如何对 JSON 串进行反转义...

    简单概括PHP的字符串中单引号与双引号的区别

    - **单引号**:单引号只支持少数转义序列,如`\''`(单引号)和`\\`(反斜杠)。对于`\n`这样的转义序列,单引号字符串会将其视为普通字符,如`echo 'hello is $hello\n';`将原样输出包含`\n`的字符串。 3. **性能...

Global site tag (gtag.js) - Google Analytics