设为首页 收藏本站
查看: 933|回复: 0

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

[复制链接]

尚未签到

发表于 2017-5-16 09:16:36 | 显示全部楼层 |阅读模式
  我们知道在shell中有两类字符,一类是普通字符(literal),在shell中没有任何特殊意义;另一类是所谓“元字符”(meta),在shell中有特殊的含义或用法。

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

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

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

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

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

  • $ echo \\
  • \
  • $ echo "\\"
  • \
  • $ echo '\'
  • \

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

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

  • $ echo \\\\
  • \\
  • $ echo "\\\\"
  • \\
  • $ echo '\\'
  • \\

[color=#336699 !important]复制代码
  
嗯,好像没有什么奇怪的事发生,我们简单地使用双倍的\就搞定了。

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

  • $ echo \\
  • \
  • $ echo "\\"
  • \
  • $ echo '\'
  • \

[color=#336699 !important]复制代码
  
这个容易,简单的重复罢了。再来两个\:

  • $ echo \\\\
  • \
  • $ echo "\\\\"
  • \
  • $ echo '\\'
  • \

[color=#336699 !important]复制代码
  
等等,怎么搞的?为什么只输出了一个\?
再加一个\会如何?

  • $ echo \\\\\
  • >
  • \
  • $ echo \\\\\\
  • \\
  • $ echo "\\\\\"
  • >
  • \
  • $ echo "\\\\\\"
  • \\
  • $ echo '\\'
  • \\

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

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

  • 输出        命令行需要\的个数
  • \        2/4
  • \\       6/8
  • \\\      10/12
  • \\\\     14/16
  • \\\\\   18/20
  • ...       ...
  • n个\    4n-2/4n

[color=#336699 !important]复制代码
  
厌倦了吗?其实ksh下除了用',还有其它方法剪断这“懒婆娘的裹脚布”。窍门就在于echo命令的-E选项:

  • $ echo -E \\
  • \
  • $ echo -E \\\\
  • \\
  • $ echo -E \\\\\\
  • \\\

[color=#336699 !important]复制代码
  
很好!这样与bash下的情况就一样了,-E选项是不是很神奇呀!为什么呢?

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

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

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

  • $ set -x
  • $ echo \\\\
  • + echo \\
  • \

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

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

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

  • $echo C:\\tmp | sed 's/\\/&\\/'
  • C:        mp
  • $echo 'C:\abc'|sed 's/\\/\\\\/'
  • C:bc

[color=#336699 !important]复制代码
  
在看过上面我们对引用和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呢?改法可能不止一种,不过这个还是留给亲爱的读者您作为一个练习好了。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-377930-1-1.html 上篇帖子: shell中的括号(小括号,中括号,大括号/花括号) 下篇帖子: shell自动化部署批量建立用户和批量SSH配置
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表