shell十三问之4:""(双引号)与''(单引号)差在哪?

发表于 5年以前  | 总阅读数:1582 次

shell十三问之4:""(双引号)与''(单引号)差在哪?

还是回到我们的command line来吧...

经过前面两章的学习,应该很清楚当你在shell prompt后面敲打键盘, 直到按下Enter键的时候,你输入的文字就是command line了, 然后shell才会以进程的方式执行你所交给它的命令。 但是,你又可知道:你在command line中输入的每一个文字, 对shell来说,是有类别之分的呢?

简单而言,(我不敢说精确的定义,注1), command line的每一个charactor, 分为如下两种:

  • literal:也就是普通的纯文字,对shell来说没特殊功能;
  • meta: 对shell来说,具有特定功能的特殊保留元字符。

Note:

对于bash shell在处理comamnd line的顺序说明, 请参考O'Reilly出版社的Learning the Bash Shell,2nd Edition, 第177-180页的说明,尤其是178页的流程图:Figure 7-1 ...

literal没什么好谈的, 像abcd、123456这些"文字"都是literal...(so easy? ^_^) 但meta却常使我们困惑...(confused?) 事实上,前两章,我们在command line中已碰到两个 似乎每次都会碰到的meta:

  • IFS:有space或者tab或者Enter三者之一组成(我们常用space)
  • CR: 由Enter产生;

IFS是用来拆解command line中每一个词(word)用的, 因为shell command line是按词来处理的。 而CR则是用来结束command line用的,这也是为何我们敲Enter键, 命令就会跑的原因。

除了常用的IFSCR, 常用的meta还有:

meta字符 meta字符作用
= 设定变量
$ 作变量或运算替换(请不要与shell prompt混淆)
> 输出重定向(重定向stdout)
< 输入重定向(重定向stdin)
| 命令管道
& 重定向file descriptor或将命令至于后台(bg)运行
() 将其内部的命令置于nested subshell执行,或用于运算或变量替换
{} 将期内的命令置于non-named function中执行,或用在变量替换的界定范围
; 在前一个命令执行结束时,而忽略其返回值,继续执行下一个命令
&& 在前一个命令执行结束时,若返回值为true,继续执行下一个命令
|| 在前一个命令执行结束时,若返回值为false,继续执行下一个命令
! 执行histroy列表中的命令
... ...

假如我们需要在command line中将这些保留元字符的功能关闭的话, 就需要quoting处理了。

bash中,常用的quoting有以下三种方法:

  • hard quote:''(单引号),凡在hard quote中的所有meta均被关闭;
  • soft quote:""(双引号),凡在soft quote中大部分meta都会被关闭,但某些会保留(如$);
  • escape: \ (反斜杠),只有在紧接在escape(跳脱字符)之后的单一meta才被关闭;

Note:

在soft quote中被豁免的具体meta清单,我不完全知道, 有待大家补充,或通过实践来发现并理解。

下面的例子将有助于我们对quoting的了解:

$ A=B C #空白符未被关闭,作为IFS处理
$ C:command not found.
$ echo $A

$ A="B C" #空白符已被关掉,仅作为空白符
$ echo $A
B C

在第一个给A变量赋值时,由于空白符没有被关闭, command line 将被解释为: A=B 然后碰到<IFS>,接着执行C命令 在第二次给A变量赋值时,由于空白符被置于soft quote中, 因此被关闭,不在作为IFSA=B<space>C 事实上,空白符无论在soft quote还是在hard quote中, 均被关闭。Enter键字符亦然:

$ A=`B
> C
> '
$ echo "$A"
B
C

在上例中,由于enter被置于hard quote当中,因此不再作为CR字符来处理。 这里的enter单纯只是一个断行符号(new-line)而已, 由于command line并没得到CR字符, 因此进入第二个shell prompt(PS2, 以>符号表示), command line并不会结束,直到第三行, 我们输入的enter并不在hard quote里面, 因此没有被关闭, 此时,command line碰到CR字符,于是结束,交给shell来处理。

上例的Enter要是被置于soft quote中的话,CR字符也会同样被关闭:

$ A="B
> C
> "
$ echo $A
B C

然而,由于 echo $A时的变量没有置于soft quote中, 因此,当变量替换完成后,并作命令行重组时,enter被解释为IFS, 而不是new-line字符。

同样的,用escape亦可关闭CR字符:

$ A=B\
> C\
>
$ echo $A
BC

上例中的,第一个enter跟第二个enter均被escape字符关闭了, 因此也不作为CR来处理,但第三个enter由于没有被escape, 因此,作为CR结束command line。 但由于enter键本身在shell meta中特殊性,在 \ escape字符后面 仅仅取消其CR功能, 而不保留其IFS功能。

你或许发现光是一个enter键所产生的字符,就有可能是如下这些可能:

  • CR
  • IFS
  • NL(New Line)
  • FF(Form Feed)
  • NULL
  • ...

至于,什么时候解释为什么字符,这个我就没法去挖掘了, 或者留给读者君自行慢慢摸索了...^-^

至于soft quote跟hard quote的不同,主要是对于某些meta的关闭与否,以$来做说明:

$ A=B\ C
$ echo "$A"
B C
$ echo '$A'
$A

在第一个echo命令行中,$被置于soft quote中,将不被关闭, 因此继续处理变量替换, 因此,echo将A的变量值输出到屏幕,也就是"B C"的结果。

在第二个echo命令行中,$被置于hard quote中,则被关闭, 因此,$只是一个$符号,并不会用来做变量替换处理, 因此结果是$符号后面接一个A字母:$A.

练习与思考: 如下结果为何不同?

tips: 单引号和双引号,在quoting中均被关闭了。

$ A=B\ C
$ echo '"$A"'  #最外面的是单引号
"$A"
$ echo "'$A'"  #最外面的是双引号
'B C'

在CU的shell版里,我发现很多初学者的问题, 都与quoting的理解有关。 比方说,若我们在awk或sed的命令参数中, 调用之前设定的一些变量时,常会问及为何不能的问题。

要解决这些问题,关键点就是:区分出 shell meta 与 command meta

前面我们提到的那些meta,都是在command line中有特殊用途的, 比方说{}就是将一系列的command line置于不具名的函数中执行(可简单视为command block), 但是,awk却需要用{}来区分出awk的命令区段(BEGIN,MAIN,END). 若你在command line中如此输入:

$ awk {print $0} 1.txt

由于{}在shell中并没有关闭,那shell就将{print $0}视为command block, 但同时没有;符号作命令分隔,因此,就出现awk语法错误结果。

要解决之,可用hard quote:

awk '{print $0}'

上面的hard quote应好理解,就是将原来的 {、、$、}这几个shell meta关闭, 避免掉在shell中遭到处理,而完整的成为awk的参数中command meta。

Note:

awk中使用的$0 是awk中内建的field nubmer,而非awk的变量, awk自身的变量无需使用$.

要是理解了hard quote的功能,在来理解soft quote与escape就不难:

awk "{print \$0}" 1.txt
awk \{print \$0\} 1.txt

然而,若要你改变awk的$0的0值是从另一个shell变量中读进呢? 比方说:已有变量$A的值是0, 那如何在command line中解决 awk的$$A呢? 你可以很直接否定掉hard quote的方案:

$ awk '{print $$A}' 1.txt

那是因为$A的$在hard quote中是不能替换变量的。

聪明的读者(如你!),经过本章的学习,我想,你应该可以理解为 为何我们可以使用如下操作了吧:

A=0
awk "{print \$$A}" 1.txt
awk  \{print\ \$$A\} 1.txt
awk '{print $'$A'}' 1.txt
awk '{print $'"$A"'}' 1.txt

或许,你能给出更多方案... ^_^

更多练习:

  • http://bbs.chinaunix.net/forum/viewtopic.php?t=207178 一个关于read命令的小问题: 很早以前觉得很奇怪:执行read命令,然后读取用户输入给变量赋值, 但如果输入是以空格键开始的话,这空格会被忽略,比如:
    read a  #输入:    abc
    echo "$a" #只输出abc

    原因: 变量a的值,从终端输入的值是以IFS开头,而这些IFS将被shell解释器忽略(trim)。 应该与shell解释器分词的规则有关;

read a  #输入:\ \ \ abc
echo "$a" #只输出abc

需要将空格字符转义

Note:

IFS Internal field separators, normally space, tab, and newline (see Blank Interpretation section). ...... Blank Interpretation After parameter and command substitution, the results of substitution
are scanned for internal field separator characters (those found in IFS) and split into distinct arguments where such characters are found. Explicit null arguments ("" or '') are retained.
Implicit null arguments(those resulting from parameters that have no values) are removed. (refre to: man sh)

解决思路:

  1. shell command line 主要是将整行line给分解(break down)为每一个单词(word);
  2. 而词与词之间的分隔符就是IFS (Internal Field Seperator)。
  3. shell会对command line作处理(如替换,quoting等), 然后再按词重组。(注:别忘了这个重组特性)
  4. 当你用IFS来事开头一个变量值,那shell会先整理出这个词,然后在重组command line。 5.然而,你将IFS换成其他,那shell将视你哪些space/tab为“词”,而不是IFS。那在重组时,可以得到这些词。

若你还是不理解,那来验证一下下面这个例子:

$ A="  abc" 
$ echo $A
abc
$ echo "$A" #note1
   abc
$ old_IFS=$IFS
$ IFS=;
$ echo $A
   abc
$ IFS=$old_IFS
$ echo $A
abc

Note:

  1. 这里是用 soft quoting 将里面的 space 关闭,使之不是 meta(IFS), 而是一个literal(white space);
  1. IFS=; 意义是将IFS设置为空字符,因为;是shell的元字符(meta);

问题二:为什么多做了几个分号,我想知道为什么会出现空格呢?

$ a=";;;test"                              
$ IFS=";"                                  
$ echo $a                                  
   test                                                                         
$ a="   test"                              
$ echo $a                                  
   test                                                                         
$ IFS=" "                                  
$ echo $a                                  
test    

解答:

这个问题,出在IFS=;上。 因为这个;在问题一中的command line上是一个meta, 并非";"符号本身。 因此,IFS=;是将IFS设置为 null charactor (不是space、tab、newline)。

要不是试试下面这个代码片段:

$ old_IFS=$IFS
$ read A
;a;b;c
$ echo $A
;a;b;c
$ IFS=";"  #Note2
$ echo $A
a b c

Note:

要关闭;可用";"或者';'或者\;

  • http://bbs.chinaunix.net/forum/viewtopic.php?t=216729

思考问题二:文本处理:读文件时,如何保证原汁原味。

cat file | while read i
do
   echo $i
done

文件file的行中包含若干空,经过read只保留不重复的空格。 如何才能所见即所得。

cat file | while read i
do
   echo "X${i}X"
done

从上面的输出,可以看出read,读入是按整行读入的; 不能原汁原味的原因:

  1. 如果行的起始部分有IFS之类的字符,将被忽略;
  2. echo $i的解析过程中,首先将$i替换为字符串, 然后对echo 字符串中字符串分词,然后命令重组,输出结果; 在分词,与命令重组时,可能导致多个相邻的IFS转化为一个;
cat file | while read i
do
  echo "$i"
done

以上代码可以解决原因2中的,command line的分词和重组导致meta字符丢失; 但仍然解决不了原因1中,read读取行时,忽略行起始的IFS meta字符。

回过头来看上面这个问题:为何要原汁原味呢? cat命令就是原汁原味的,只是shell的read、echo导致了某些shell的meta字符丢失;

如果只是IFS meta的丢失,可以采用如下方式: 将IFS设置为null,即IFS=;, 在此再次重申此处;是shell的meta字符,而不是literal字符; 因此要使用literal的 ;应该是\; 或者关闭meta 的(soft/hard) quoting的";"或者';'

因此上述的解决方案是:

old_IFS=$IFS
IFS=; #将IFS设置为null
cat file | while read i
do
  echo "$i"
done
IFS=old_IFS #恢复IFS的原始值

现在,回过头来看这个问题,为什么会有这个问题呢; 其本源的问题应该是没有找到解决原始问题的最合适的方法, 而是采取了一个迂回的方式来解决了问题;

因此,我们应该回到问题的本源,重新审视一下,问题的本质。 如果要精准的获取文件的内容,应该使用od或者hexdump会更好些。

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
如何查看docker镜像里的文件 5年以前  |  5480次阅读
Shell语法快速入门 5年以前  |  3160次阅读
Shell命令在后台运行程序 5年以前  |  3069次阅读
Shell脚本编程30分钟入门 5年以前  |  1892次阅读
 目录