""(雙引號) 與''(單引號) 差在哪?

還是回到我們的command line來吧...

經(jīng)過前面兩章的學(xué)習(xí)讥耗,應(yīng)該很清楚當(dāng)你在shell prompt后面敲打鍵盤, 直到按下Enter鍵的時候有勾,你輸入的文字就是command line了, 然后shell才會以進(jìn)程的方式執(zhí)行你所交給它的命令古程。 但是蔼卡,你又可知道:你在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?) 事實(shí)上,前兩章赏僧,我們在command line中已碰到兩個 似乎每次都會碰到的 meta:

  • IFS:有space或者tab或者Enter三者之一組成 (我們常用 space)
  • CR: 由Enter產(chǎn)生大猛;

IFS是用來拆解command line中每一個詞 (word) 用的, 因?yàn)?code>shell command line是按詞來處理的淀零。 而CR則是用來結(jié)束command line用的挽绩,這也是為何我們敲Enter鍵, 命令就會跑的原因驾中。

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

meta 字符 meta 字符作用
= 設(shè)定變量
$ 作變量或運(yùn)算替換 (請不要與shell prompt混淆)
> 輸出重定向 (重定向 stdout)
< 輸入重定向 (重定向 stdin)
| 命令管道
& 重定向 file descriptor 或?qū)⒚钪劣诤笈_ (bg) 運(yùn)行
() 將其內(nèi)部的命令置于 nested subshell 執(zhí)行唉堪,或用于運(yùn)算或變量替換
{} 將期內(nèi)的命令置于 non-named function 中執(zhí)行,或用在變量替換的界定范圍
; 在前一個命令執(zhí)行結(jié)束時肩民,而忽略其返回值唠亚,繼續(xù)執(zhí)行下一個命令
&& 在前一個命令執(zhí)行結(jié)束時,若返回值為 true持痰,繼續(xù)執(zhí)行下一個命令
|| 在前一個命令執(zhí)行結(jié)束時灶搜,若返回值為 false,繼續(xù)執(zhí)行下一個命令
! 執(zhí)行 histroy 列表中的命令
... ...

假如我們需要在command line中將這些保留元字符的功能關(guān)閉的話, 就需要 quoting 處理了割卖。

bash中前酿,常用的 quoting 有以下三種方法:

  • hard quote:''(單引號),凡在 hard quote 中的所有 meta 均被關(guān)閉究珊;
  • soft quote:""(雙引號)薪者,凡在 soft quote 中大部分 meta 都會被關(guān)閉,但某些會保留 (如 $);
  • escape: \ (反斜杠)剿涮,只有在緊接在 escape(跳脫字符) 之后的單一 meta 才被關(guān)閉言津;

Note:

在 soft quote 中被豁免的具體 meta 清單,我不完全知道取试, 有待大家補(bǔ)充悬槽,或通過實(shí)踐來發(fā)現(xiàn)并理解。

下面的例子將有助于我們對 quoting 的了解:

$ A=B C #空白符未被關(guān)閉瞬浓,作為IFS處理
$ C:command not found.
$ echo $A
$ A="B C" #空白符已被關(guān)掉初婆,僅作為空白符
$ echo $A
B C

在第一個給 A 變量賦值時,由于空白符沒有被關(guān)閉猿棉, command line 將被解釋為: A=B 然后碰到<IFS>磅叛,接著執(zhí)行C命令 在第二次給 A 變量賦值時,由于空白符被置于 soft quote 中萨赁, 因此被關(guān)閉弊琴,不在作為IFSA=B<space>C 事實(shí)上杖爽,空白符無論在 soft quote 還是在 hard quote 中敲董, 均被關(guān)閉。Enter 鍵字符亦然:

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

在上例中慰安,由于enter被置于 hard quote 當(dāng)中腋寨,因此不再作為CR字符來處理。 這里的enter單純只是一個斷行符號 (new-line) 而已化焕, 由于command line并沒得到CR字符萄窜, 因此進(jìn)入第二個shell prompt(PS2,以 > 符號表示)撒桨, command line并不會結(jié)束脂倦,直到第三行, 我們輸入的enter并不在 hard quote 里面元莫, 因此沒有被關(guān)閉赖阻, 此時,command line碰到CR字符踱蠢,于是結(jié)束火欧,交給 shell 來處理棋电。

上例的Enter要是被置于 soft quote 中的話,CR字符也會同樣被關(guān)閉:

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

然而苇侵,由于 echo $A時的變量沒有置于 soft quote 中赶盔, 因此,當(dāng)變量替換完成后榆浓,并作命令行重組時于未,enter被解釋為IFS, 而不是 new-line 字符陡鹃。

同樣的烘浦,用 escape 亦可關(guān)閉 CR 字符:

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

上例中的,第一個enter跟第二個enter均被 escape 字符關(guān)閉了萍鲸, 因此也不作為CR來處理闷叉,但第三個enter由于沒有被 escape, 因此脊阴,作為CR結(jié)束command line握侧。 但由于enter鍵本身在 shell meta 中特殊性,在 \ escape 字符后面 僅僅取消其CR功能嘿期, 而不保留其 IFS 功能品擎。

你或許發(fā)現(xiàn)光是一個enter鍵所產(chǎn)生的字符,就有可能是如下這些可能:

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

至于备徐,什么時候解釋為什么字符萄传,這個我就沒法去挖掘了, 或者留給讀者君自行慢慢摸索了...-

至于 soft quote 跟 hard quote 的不同坦喘,主要是對于某些 meta 的關(guān)閉與否,以 $ 來做說明:

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

在第一個echo命令行中西设,$ 被置于 soft quote 中瓣铣,將不被關(guān)閉, 因此繼續(xù)處理變量替換贷揽, 因此棠笑,echo將 A 的變量值輸出到屏幕,也就是 "B C" 的結(jié)果禽绪。

在第二個echo命令行中蓖救,<nobr>被置于hardquote中,則被關(guān)閉印屁,因此循捺,</nobr> 只是一個 <nobr>符號,并不會用來做變量替換處理雄人,因此結(jié)果是</nobr> 符號后面接一個 A 字母:$A从橘。

練習(xí)與思考: 如下結(jié)果為何不同念赶?

tips: 單引號和雙引號,在 quoting 中均被關(guān)閉了恰力。

$ A=B\ C
$ echo '"$A"'  #最外面的是單引號
"$A"
$ echo "'$A'"  #最外面的是雙引號
'B C'

在 CU 的 shell 版里叉谜,我發(fā)現(xiàn)很多初學(xué)者的問題, 都與 quoting 的理解有關(guān)踩萎。 比方說停局,若我們在 awk 或 sed 的命令參數(shù)中, 調(diào)用之前設(shè)定的一些變量時香府,常會問及為何不能的問題董栽。

要解決這些問題,關(guān)鍵點(diǎn)就是:區(qū)分出 shell meta 與 command meta

前面我們提到的那些 meta回还,都是在 command line 中有特殊用途的裆泳, 比方說 {} 就是將一系列的 command line 置于不具名的函數(shù)中執(zhí)行 (可簡單視為 command block), 但是柠硕,awk 卻需要用 {} 來區(qū)分出 awk 的命令區(qū)段 (BEGIN,MAIN,END). 若你在 command line 中如此輸入:

 `$ awk {print $0} 1.txt`

由于 {} 在 shell 中并沒有關(guān)閉工禾,那 shell 就將 {print $0} 視為 command block, 但同時沒有;符號作命令分隔蝗柔,因此闻葵,就出現(xiàn) awk 語法錯誤結(jié)果。

要解決之癣丧,可用 hard quote:

`awk '{print $0}'`

上面的 hard quote 應(yīng)好理解槽畔,就是將原來的 {、胁编、$厢钧、} 這幾個 shell meta 關(guān)閉, 避免掉在 shell 中遭到處理嬉橙,而完整的成為 awk 的參數(shù)中 command meta早直。

Note:

awk 中使用的 <nobr>0是awk中內(nèi)建的fieldnubmer,而非awk的變量市框,awk自身的變量無需使用</nobr>霞扬。

要是理解了 hard quote 的功能,在來理解 soft quote 與 escape 就不難:

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

然而枫振,若要你改變 awk 的 <nobr>0的0值是從另一個shell變量中讀進(jìn)呢喻圃?比方說:已有變量</nobr>A 的值是 0, 那如何在command line中解決 awk 的 $$A 呢粪滤? 你可以很直接否定掉 hard quote 的方案:

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

那是因?yàn)?<nobr>A的</nobr> 在 hard quote 中是不能替換變量的斧拍。

聰明的讀者 (如你!)杖小,經(jīng)過本章的學(xué)習(xí)饮焦,我想怕吴,你應(yīng)該可以理解為 為何我們可以使用如下操作了吧:

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

或許舔琅,你能給出更多方案... _

更多練習(xí):

  • http://bbs.chinaunix.net/forum/viewtopic.php?t=207178 一個關(guān)于 read 命令的小問題: 很早以前覺得很奇怪:執(zhí)行 read 命令滋将,然后讀取用戶輸入給變量賦值, 但如果輸入是以空格鍵開始的話戈毒,這空格會被忽略硼啤,比如:
read a  #輸入:    abc
echo "$a" #只輸出abc

原因: 變量 a 的值议经,從終端輸入的值是以 IFS 開頭,而這些 IFS 將被 shell 解釋器忽略 (trim)谴返。 應(yīng)該與 shell 解釋器分詞的規(guī)則有關(guān)煞肾;

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

需要將空格字符轉(zhuǎn)義

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. 當(dāng)你用 IFS 來事開頭一個變量值,那 shell 會先整理出這個詞渠抹,然后在重組 command line蝙昙。
  5. 然而,你將 IFS 換成其他梧却,那 shell 將視你哪些 space/tab 為 “詞”奇颠,而不是 IFS。那在重組時放航,可以得到這些詞烈拒。

若你還是不理解,那來驗(yàn)證一下下面這個例子:

$ 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 關(guān)閉广鳍,使之不是 meta(IFS)荆几, 而是一個 literal(white space);
  1. IFS=; 意義是將 IFS 設(shè)置為空字符,因?yàn)? 是 shell 的元字符 (meta);

問題二:為什么多做了幾個分號赊时,我想知道為什么會出現(xiàn)空格呢吨铸?

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

解答:

這個問題,出在IFS=;上蛋叼。 因?yàn)檫@個;在問題一中的 command line 上是一個 meta, 并非";"符號本身焊傅。 因此剂陡,IFS=;是將 IFS 設(shè)置為 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:
要關(guān)閉;可用";"或者';'或者\;歌馍。

思考問題二:文本處理:讀文件時,如何保證原汁原味晕鹊。

cat file | while read i
do
   echo $i
done

文件 file 的行中包含若干空松却,經(jīng)過 read 只保留不重復(fù)的空格暴浦。 如何才能所見即所得。

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

從上面的輸出晓锻,可以看出 read歌焦,讀入是按整行讀入的; 不能原汁原味的原因:

  1. 如果行的起始部分有 IFS 之類的字符,將被忽略;
  2. echo $i的解析過程中砚哆,首先將 $i 替換為字符串独撇, 然后對 echo 字符串中字符串分詞,然后命令重組躁锁,輸出結(jié)果; 在分詞纷铣,與命令重組時,可能導(dǎo)致多個相鄰的 IFS 轉(zhuǎn)化為一個;
cat file | while read i
do
  echo "$i"
done

以上代碼可以解決原因 2 中的战转,command line 的分詞和重組導(dǎo)致 meta 字符丟失搜立; 但仍然解決不了原因 1 中,read 讀取行時槐秧,忽略行起始的 IFS meta 字符啄踊。

回過頭來看上面這個問題:為何要原汁原味呢? cat 命令就是原汁原味的色鸳,只是 shell 的 read社痛、echo 導(dǎo)致了某些 shell 的 meta 字符丟失;

如果只是 IFS meta 的丟失,可以采用如下方式: 將 IFS 設(shè)置為 null命雀,即IFS=;蒜哀, 在此再次重申此處;是 shell 的 meta 字符, 而不是 literal 字符; 因此要使用 literal 的 ;應(yīng)該是\; 或者關(guān)閉 meta 的 (soft/hard) quoting 的";"或者';'

因此上述的解決方案是:

old_IFS=$IFS
IFS=; #將IFS設(shè)置為null
cat file | while read i
do
  echo "$i"
done
IFS=old_IFS #恢復(fù)IFS的原始值

現(xiàn)在吏砂,回過頭來看這個問題撵儿,為什么會有這個問題呢; 其本源的問題應(yīng)該是沒有找到解決原始問題的最合適的方法狐血, 而是采取了一個迂回的方式來解決了問題淀歇;

因此,我們應(yīng)該回到問題的本源匈织,重新審視一下浪默,問題的本質(zhì)。 如果要精準(zhǔn)的獲取文件的內(nèi)容缀匕,應(yīng)該使用 od 或者 hexdump 會更好些纳决。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市乡小,隨后出現(xiàn)的幾起案子阔加,更是在濱河造成了極大的恐慌,老刑警劉巖满钟,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胜榔,死亡現(xiàn)場離奇詭異胳喷,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)夭织,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進(jìn)店門吭露,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人尊惰,你說我怎么就攤上這事奴饮。” “怎么了择浊?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵戴卜,是天一觀的道長。 經(jīng)常有香客問我琢岩,道長投剥,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任担孔,我火速辦了婚禮江锨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘糕篇。我一直安慰自己啄育,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布拌消。 她就那樣靜靜地躺著挑豌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪墩崩。 梳的紋絲不亂的頭發(fā)上氓英,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天,我揣著相機(jī)與錄音鹦筹,去河邊找鬼铝阐。 笑死,一個胖子當(dāng)著我的面吹牛铐拐,可吹牛的內(nèi)容都是我干的徘键。 我是一名探鬼主播,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼遍蟋,長吁一口氣:“原來是場噩夢啊……” “哼吹害!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起匿值,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤赠制,失蹤者是張志新(化名)和其女友劉穎赂摆,沒想到半個月后挟憔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钟些,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年绊谭,在試婚紗的時候發(fā)現(xiàn)自己被綠了政恍。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡达传,死狀恐怖篙耗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情宪赶,我是刑警寧澤宗弯,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站搂妻,受9級特大地震影響蒙保,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜欲主,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一邓厕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧扁瓢,春花似錦详恼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至伟桅,卻和暖如春硅堆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背贿讹。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工渐逃, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人民褂。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓茄菊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親赊堪。 傳聞我的和親對象是個殘疾皇子面殖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容