shell單引號雙引號詳解


linux shell中的單引號與雙引號的區別(看完就不會有引號的疑問了)

" "(雙引號)與 ' '(單引號)的區別 

 

  你在shell prompt(shell 提示)后面敲打鍵盤、直到按下enter的時候,你輸入的文字就是command line(命令行)了,然后shell才會以進程方式執行你所提交的命令。但是,你又可知道:你在command line輸入的每一個文字,對shell來說,有什么類別之分呢?

簡單而言,command line的每一個charactor(字符)分為如下兩種:
  *literal(文字):也就是普通純文字,對shell來說沒有特殊功能。
  *meta(元字符):對shell來說,具有特定功能的保留字。
literal沒有什么好說的,凡是 abcd、123456 等這些“文字”都是literal。但是meta卻常使我們困惑。事實上,前兩章我們在command line中已碰到兩個幾乎每次都會碰到的meta:
   *IFS(交換字段分隔符):由<space> <tab> <enter>三者之一組成(我們常用space)。
   *CR(回車鍵):由<enter>產生。
IFS是用來拆分command line的每一個詞(word)用的,因為shell command line是按詞來處理的。而CR則是用來結束command line用的,這也是為何我們敲<enter>命令就會執行的原因。除了IFS和CR外,常用的meta還有:
= :  設定變量。
$ :  做變量或運算替換(請不要與 shell prompt 搞混了)。
> :  重定向 stdout(標准輸出standard out)。
< :  重定向 stdin(標准輸入standard in)。
|:   管道命令。
& :  重定向 file descriptor (文件描述符),或將命令置於后台執行。
( ): 將其內的命令置於 nested subshell (嵌套的子shell)執行,或用於運算或命令替換。
{ }: 將其內的命令置於 non-named function(未命名函數) 中執行,或用在變量替換的界定范圍。
; :  在前一個命令結束時,而忽略其返回值,繼續執行下一個命令。
&& : 在前一個命令結束時,若返回值為 true,繼續執行下一個命令。
|| : 在前一個命令結束時,若返回值為 false,繼續執行下一個命令。
!:   執行 history 列表中的命令
....
假如我們要在command line中將這些保留元字符的功能關閉的話,就要用到 quoting (引用)處理了。
在bash中,我們常用的 quoting有如下三種方法:
   *hard quote:''(單引號),凡在hard quote中的所有meta均被關閉。
   *soft quote:""(雙引號),在soft quote中的大部分meta都會被關閉,但某些保留(如$)。
   *escape:\ (反斜線),只有緊接在escape(跳脫字符)之后的單一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 中,因此被關閉,不再作為 IFS :
* A=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> 由於沒有被跳脫,因此作為 CR 結束 command line 。
但由於 <enter> 鍵本身在 shell meta 中的特殊性,在 \ 跳脫后面,僅僅取消其 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 。

---------------------------------------------------------
練習與思考:以下兩條命令輸出的結果分別是什么?
       $ A=B\ C
       $ echo '"$A"'        # 最外面的是單引號

       $ echo "'$A'"        # 最外面的是雙引號

----------------------------------------------------------------

【認真閱讀文章,答案自會揭曉】

-------------------------------------------------------

下面為擴展閱讀,難度有點大,初級同學建議學懂上面的就好。以后再做拓展也可以。

***************************************************************************************                                                          

在 CU 的 shell 版里,我發現有很多初學者的問題,都與 quoting 理解的有關。
比方說,若我們在 awk 或 sed 的命令參數中調用之前設定的一些變量時,常會問及為何不能的問題。
要解決這些問題,關鍵點就是:
* 區分出 shell meta 與 command meta 

前面我們提到的那些 meta ,都是在 command line 中有特殊用途的,
比方說 { } 是將其內一系列 command line 置於不具名的程序中執行(可簡單視為 command block ),
但是,awk 卻需要用 { } 來區分出 awk 的命令區段(BEGIN, MAIN, END)。
若你在 command line 中如此輸入:
1
2
3
[root@jasontest01 ~]# awk {print $0} 1.txt   #這里$0由shell解釋
awk: cmd. line:1: {print
awk: cmd. line:1:       ^ unexpected newline or end of string

 

由於  { } 在 shell 中並沒關閉,那 shell 就將 {print $0} 視為 command block ,
但同時又沒有" ; "符號作命令區隔,因此就出現 awk 的語法錯誤結果。

要解決之,可用 hard quote :

 

1
2
3
4
5
6
[root@jasontest01 ~] # awk '{print $0}' 1.txt    #而這里因為有''作用,所以$0其實是由awk程序解釋
i am student
my teacher is oldboy
i am very happy
i come from guangzhou
now i am  in  beijing

 

上面的 hard quote 應好理解,就是將原本的 {、<space>、$(注三)、} 這幾個 shell meta 關閉,
避免掉在 shell 中遭到處理,而完整的成為 awk 參數中的 command meta 。
( 注三:而其中的 $0 是 awk 內建的 field number ,而非  awk 的變量,
awk 自身的變量無需使用 $ 。)
要是理解了 hard quote 的功能,再來理解 soft quote 與 escape 就不難:

1
2
3
4
5
6
[root@jasontest01 ~] # awk "{print \$0}" 1.txt
i am student
my teacher is oldboy
i am very happy
i come from guangzhou
now i am  in  beijing

 

 

1
2
3
4
5
6
[root@jasontest01 ~] # awk \{print\ \$0\} 1.txt
i am student
my teacher is oldboy
i am very happy
i come from guangzhou
now i am  in  beijing

 

然而,若你要改變 awk 的 $0 的 0 值是從另一個 shell 變量讀進呢?
比方說:已有變量 $A 的值是 0 ,那如何在 command line 中解決 awk 的 $$A 呢?
你可以很直接否定掉 hard quoe 的方案:

$ 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     # 注:"$A" 包在 soft quote 中,,此處也要注意''與""的結合

單引號和雙引號都能關閉shell對特殊字符的處理。不同的是,雙引號沒有單引號嚴格,單引號關閉所有有特殊作用的字符,而雙引號只要求shell忽略大多數,具體的說,就是①美元符號②反引號③反斜杠,這3種特殊字符不被忽略。 不忽略美元符號意味着shell在雙引號內部也進行變量名替換。

下面用一個簡單的shell程序要說明一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
debian:~ /learn/shell # cat phonebook
Alice Chebba 973-555-2015
Barbara Swingle 201-555-9257
Liz Stachiw 212-555-2298
Susan Goldberg 201-555-7776
Susan Topple 212-555-4932
Tony Iannino 973-555-1295
Stromboli Pizza 973-555-9478
debian:~ /learn/shell #
debian:~ /learn/shell # cat lu
# Look someone up in the phone book
grep  "$1"  phonebook
debian:~ /learn/shell #

這是正確的lu程序,下面是運行結果。

1
2
3
4
5
debian:~ /learn/shell # ./lu 'Susan T'
Susan Topple 212-555-4932
debian:~ /learn/shell # ./lu Tony
Tony Iannino 973-555-1295
debian:~ /learn/shell #

如果lu寫成①grep $1 phonebook或者②grep '$1' phonebook,就會出現下面的錯誤結果(為什么?)。

①的結果:

1
2
3
4
5
6
7
debian:~ /learn/shell # ./lu Tony //這種情況結果正確
Tony Iannino 973-555-1295
debian:~ /learn/shell # ./lu 'Susan T' //這種情況結果錯誤
grep : T: No such  file  or directory
phonebook:Susan Goldberg 201-555-7776
phonebook:Susan Topple 212-555-4932
debian:~ /learn/shell #

②的結果:

1
2
3
debian:~ /learn/shell # ./lu Tony //這種情況結果錯誤
debian:~ /learn/shell # ./lu 'Susan T' //這種情況結果也錯誤
debian:~ /learn/shell #

 

————————————————————————————————

 

輸出結果:(思考,為什么不同?)

$ A=B\ C

$ echo '"$A"'        # 最外面的是單引號

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

參考:http://bbs.chinaunix.net/thread-2076396-1-1.html

本文出自 “Lisp的運維之路” 博客,請務必保留此出處http://lspgyy.blog.51cto.com/5264172/1282107


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM