" "(雙引號(hào))與 ' '(單引號(hào))的區(qū)別 簡(jiǎn)單而言,command line的每一個(gè)charactor(字符)分為如下兩種: *literal(文字):也就是普通純文字,對(duì)shell來說沒有特殊功能。 *meta(元字符):對(duì)shell來說,具有特定功能的保留字。 literal沒有什么好說的,凡是 abcd、123456 等這些“文字”都是literal。但是meta卻常使我們困惑。事實(shí)上,前兩章我們?cè)赾ommand line中已碰到兩個(gè)幾乎每次都會(huì)碰到的meta: *IFS(交換字段分隔符):由<space> <tab> <enter>三者之一組成(我們常用space)。 *CR(回車鍵):由<enter>產(chǎn)生。 IFS是用來拆分command line的每一個(gè)詞(word)用的,因?yàn)閟hell command line是按詞來處理的。而CR則是用來結(jié)束command line用的,這也是為何我們敲<enter>命令就會(huì)執(zhí)行的原因。除了IFS和CR外,常用的meta還有: = : 設(shè)定變量。 $ : 做變量或運(yùn)算替換(請(qǐng)不要與 shell prompt 搞混了)。 > : 重定向 stdout(標(biāo)準(zhǔn)輸出standard out)。 < : 重定向 stdin(標(biāo)準(zhǔn)輸入standard in)。 |: 管道命令。 & : 重定向 file descriptor (文件描述符),或?qū)⒚钪糜诤笈_(tái)執(zhí)行。 ( ): 將其內(nèi)的命令置于 nested subshell (嵌套的子shell)執(zhí)行,或用于運(yùn)算或命令替換。 { }: 將其內(nèi)的命令置于 non-named function(未命名函數(shù)) 中執(zhí)行,或用在變量替換的界定范圍。 ; : 在前一個(gè)命令結(jié)束時(shí),而忽略其返回值,繼續(xù)執(zhí)行下一個(gè)命令。 && : 在前一個(gè)命令結(jié)束時(shí),若返回值為 true,繼續(xù)執(zhí)行下一個(gè)命令。 || : 在前一個(gè)命令結(jié)束時(shí),若返回值為 false,繼續(xù)執(zhí)行下一個(gè)命令。 !: 執(zhí)行 history 列表中的命令 .... 假如我們要在command line中將這些保留元字符的功能關(guān)閉的話,就要用到 quoting (引用)處理了。 在bash中,我們常用的 quoting有如下三種方法: *hard quote:''(單引號(hào)),凡在hard quote中的所有meta均被關(guān)閉。 *soft quote:""(雙引號(hào)),在soft quote中的大部分meta都會(huì)被關(guān)閉,但某些保留(如$)。 *escape:\ (反斜線),只有緊接在escape(跳脫字符)之后的單一meta才被關(guān)閉。 下面的例子將有助于我們對(duì) quoting 的了解: $ A=B C # 空白鍵未被關(guān)閉,作為IFS 處理。 $ C: command not found. $ echo $A $ A="B C" # 空白鍵已被關(guān)閉,僅作空白符號(hào)處理。 $ echo $A B C 在第一次設(shè)定 A 變量時(shí),由于空白鍵沒有被關(guān)閉,command line 將被解讀為: * A=B 然后碰到<IFS>,再執(zhí)行 C 命令 在第二次設(shè)定 A 變量時(shí),由于空白鍵置于 soft quote 中,因此被關(guān)閉,不再作為 IFS : * A=B<space>C 事實(shí)上,空白鍵無論在 soft quote 還是在 hard quote 中,均會(huì)被關(guān)閉。Enter 鍵亦然: $ A='B > C > ' $ echo "$A" B C 在上例中,由于 <enter> 被置于 hard quote 當(dāng)中,因此不再作為 CR 字符來處理。 這里的 <enter> 單純只是一個(gè)斷行符號(hào)(new-line)而已,由于 command line 并沒得到 CR 字符, 因此進(jìn)入第二個(gè) shell prompt (PS2,以 > 符號(hào)表示),command line 并不會(huì)結(jié)束, 直到第三行,我們輸入的 <enter> 并不在 hard quote 里面,因此并沒被關(guān)閉, 此時(shí),command line 碰到 CR 字符,于是結(jié)束、交給 shell 來處理。 上例的 <enter> 要是被置于 soft quote 中的話, CR 也會(huì)同樣被關(guān)閉: $ A="B > C > " $ echo $A B C 然而,由于 echo $A 時(shí)的變量沒置于 soft quote 中,因此當(dāng)變量替換完成后并作命令行重組時(shí),<enter> 會(huì)被解釋為 IFS ,而不是解釋為 New Line 字符。 同樣的,用 escape 亦可關(guān)閉 CR 字符: $ A=B\ > C\ > $ echo $A BC 上例中,第一個(gè) <enter> 跟第二個(gè) <enter> 均被 escape 字符關(guān)閉了,因此也不作為 CR 來處理, 但第三個(gè) <enter> 由于沒有被跳脫,因此作為 CR 結(jié)束 command line 。 但由于 <enter> 鍵本身在 shell meta 中的特殊性,在 \ 跳脫后面,僅僅取消其 CR 功能,而不會(huì)保留其 IFS 功能。 您或許發(fā)現(xiàn)光是一個(gè) <enter> 鍵所產(chǎn)生的字符就有可能是如下這些可能: CR IFS NL(New Line) FF(Form Feed) NULL ... 至于 soft quote 跟 hard quote 的不同,主要是對(duì)于某些 meta 的關(guān)閉與否,以 $ 來作說明: $ A=B\ C $ echo "$A" B C $ echo '$A' $A 在第一個(gè) echo 命令行中,$ 被置于 soft quote 中,將不被關(guān)閉,因此繼續(xù)處理變量替換, 因此 echo 將 A 的變量值輸出到屏幕,也就得到 "B C" 的結(jié)果。 在第二個(gè) echo 命令行中,$ 被置于 hard quote 中,則被關(guān)閉,因此 $ 只是一個(gè) $ 符號(hào), 并不會(huì)用來作變量替換處理,因此結(jié)果是 $ 符號(hào)后面接一個(gè) A 字母:$A 。 --------------------------------------------------------- 練習(xí)與思考:以下兩條命令輸出的結(jié)果分別是什么? $ A=B\ C $ echo '"$A"' # 最外面的是單引號(hào) $ echo "'$A'" # 最外面的是雙引號(hào) ---------------------------------------------------------------- 【認(rèn)真閱讀文章,答案自會(huì)揭曉】 ------------------------------------------------------- 下面為擴(kuò)展閱讀,難度有點(diǎn)大,初級(jí)同學(xué)建議學(xué)懂上面的就好。以后再做拓展也可以。 *************************************************************************************** 在 CU 的 shell 版里,我發(fā)現(xiàn)有很多初學(xué)者的問題,都與 quoting 理解的有關(guān)。比方說,若我們?cè)?awk 或 sed 的命令參數(shù)中調(diào)用之前設(shè)定的一些變量時(shí),常會(huì)問及為何不能的問題。 要解決這些問題,關(guān)鍵點(diǎn)就是: * 區(qū)分出 shell meta 與 command meta 前面我們提到的那些 meta ,都是在 command line 中有特殊用途的, 比方說 { } 是將其內(nèi)一系列 command line 置于不具名的程序中執(zhí)行(可簡(jiǎn)單視為 command block ), 但是,awk 卻需要用 { } 來區(qū)分出 awk 的命令區(qū)段(BEGIN, MAIN, END)。 若你在 command line 中如此輸入:
但同時(shí)又沒有" ; "符號(hào)作命令區(qū)隔,因此就出現(xiàn) awk 的語法錯(cuò)誤結(jié)果。 要解決之,可用 hard quote :
避免掉在 shell 中遭到處理,而完整的成為 awk 參數(shù)中的 command meta 。 ( 注三:而其中的 $0 是 awk 內(nèi)建的 field number ,而非 awk 的變量, awk 自身的變量無需使用 $ 。) 要是理解了 hard quote 的功能,再來理解 soft quote 與 escape 就不難:
比方說:已有變量 $A 的值是 0 ,那如何在 command line 中解決 awk 的 $$A 呢? 你可以很直接否定掉 hard quoe 的方案: $ awk '{print $$A}' 1.txt 那是因?yàn)?$A 的 $ 在 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 #此處注意'的結(jié)合方式,前面的''結(jié)合,后面的‘’結(jié)合,下同 awk '{print $'"$A"'}' 1.txt # 注:"$A" 包在 soft quote 中,,此處也要注意''與""的結(jié)合 單引號(hào)和雙引號(hào)都能關(guān)閉shell對(duì)特殊字符的處理。不同的是,雙引號(hào)沒有單引號(hào)嚴(yán)格,單引號(hào)關(guān)閉所有有特殊作用的字符,而雙引號(hào)只要求shell忽略大多數(shù),具體的說,就是①美元符號(hào)②反引號(hào)③反斜杠,這3種特殊字符不被忽略。 不忽略美元符號(hào)意味著shell在雙引號(hào)內(nèi)部也進(jìn)行變量名替換。 下面用一個(gè)簡(jiǎn)單的shell程序要說明一下。
這是正確的lu程序,下面是運(yùn)行結(jié)果。
如果lu寫成①grep $1 phonebook或者②grep '$1' phonebook,就會(huì)出現(xiàn)下面的錯(cuò)誤結(jié)果(為什么?)。 ①的結(jié)果:
②的結(jié)果:
———————————————————————————————— 輸出結(jié)果:(思考,為什么不同?) $ A=B\ C $ echo '"$A"' # 最外面的是單引號(hào) "$A" |
|