轉載:shell單引號字符' 雙引號字符" 反斜槓字符/ 反引號字符

 
1. 單引號 ( ' ' )
howard@0[script]$ grep Susan phonebook
Susan Goldberg 403-212-4921
Susan Topple    212-234-2343
如果我們想查找的是Susan Goldberg,不能直接使用grep Susan Goldberg phonebook命令,grep會把Goldberg和phonebook當作需要搜索的文件
howard@0[script]$ grep 'Susan Gold' phonebook
Susan Goldberg 403-212-4921
當shell碰到第一個單引號時,它忽略掉其後直到右引號的所有特殊字符
2. 雙引號 ( " " )
雙引號作用與單引號類似,區別在於它沒有那麼嚴格。單引號告訴shell忽略所有特殊字符,而雙引號只要求忽略大多數,具體說,括在雙引號中的三種特殊字符不被忽略:$,/,` ,即雙引號會解釋字符串的特別意思,而單引號直接使用字符串. 如果使用雙引號將字符串賦給變量並反饋它,實際上與直接反饋變量並無差別。如果要查詢包含空格的字符串,經常會用到雙引號。
howard@0[script]$ x=*
howard@0[script]$ echo $x
hello.sh menus.sh misc.sh phonebook tshift.sh
howard@0[script]$ echo '$x'
$x
howard@0[script]$ echo "$x"
*
這個例子可以看出無引號、單引號和雙引號之間的區別。在最後一種情況中,雙引號告訴shell在引號內照樣進行變量名替換,所以shell把$x替換爲*,因爲雙引號中不做文件名替換,所以就把*作爲要顯示的值傳遞給echo。
對於第一種情況需要進一步說明,shell在給變量賦值時不進行文件名替換(這從第三種情況中也能看出來),各步驟發生的精確次序如下:
shell掃描命令行,把x的值設爲星號*;
shell再次掃描命令行,碰到星號*,把它替換成當前目錄下的文件清單;
shell啓動執行echo命令,把文件清單作爲參數傳遞給echo.
這個賦值的先後次序非常重要:shell先作變量替換,然後作文件名替換,最後把這行處理爲參數
3. 反引號(``)
命令替換是指shell能夠將一個命令的標準輸出插在一個命令行中任何位置。shell中有兩種方法作命令替換:把shell命令用反引號或者$(...)結構括起來,其中,$(...)格式受到POSIX標準支持,也利於嵌套。
howard@0[script]$ echo The date and time is `date`
The date and time is 三 6月 15 06:10:35 CST 2005
howard@0[script]$ echo Your current working directory is $(pwd)
Your current working directory is /home/howard/script

4. 反斜槓 backslash-escaped( / )
反斜槓一般用作轉義字符,或稱逃脫字符,linux如果echo要讓轉義字符發生作用,就要使用-e選項,且轉義字符要使用雙引號
echo -e "/n"
反斜槓的另一種作用,就是當反斜槓用於一行的最後一個字符時,shell把行尾的反斜槓作爲續行,這種結構在分幾行輸入長命令時經常使用。

 

還是回到我們的command line來吧... 經過前面幾問的學習,應該很清楚當你在shell prompt後面敲打鍵盤、直到按下Enter的時候,你輸入的文字就是command line了,然後shell纔會以進程的方式執行你所交給它的命令。
但是,你又可知道:你在command line輸入的每一個文字,對shell來說,是有類別之分的呢?
簡單而言(我不敢說這是精確的定議),command line的每一個charactor,分爲如下兩種:
* literal:也就是普通純文字,對 shell 來說沒特殊功能。
* meta:對 shell 來說,具有特定功能的特殊保留字符。
(注:關於bash shell在處理command line時的順序說明,請參考 O'Reilly 出版社之 Learning the Bash Shell, 2nd Edition,第177-180頁的說明,尤其是178頁的流程圖Figure 7-1...)
Literal沒什麼好談的,凡舉abcd、123456這些"文字"都是literal...(easy?),但meta卻常使我們困惑..... (confused?)
事實上,前面幾問我們在 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。
< :重導向 stdin。
|:命令管線。
& :重導向 file descriptor ,或將命令置於背境執行。
( ):將其內的命令置於 nested subshell 執行,或用於運算或命令替換。
{ }:將其內的命令置於 non-named function 中執行,或用在變量替換的界定範圍。
; :在前一個命令結束時,而忽略其返回值,繼續執行下一個命令。
&& :在前一個命令結束時,若返回值爲 true,繼續執行下一個命令。
|| :在前一個命令結束時,若返回值爲 false,繼續執行下一個命令。
!:執行 history 列表中的命令
....
假如我們需要在command line中將這些保留字符的功能關閉的話,就需要 quoting 處理了。
在 bash 中,常用的 quoting 有如下三種方法:
* hard quote:' ' (單引號),凡在 hard quote 中的所有 meta 均被關閉。
* soft quote: " " (雙引號),在 soft quoe 中大部份 meta 都會被關閉,但某些則保留(如 $ )。(注:在soft quote中被豁免的具體meta清單,我不完全知道,有待大家補充,或透過實作來發現及理解。)
* escape : / (反斜線),只有緊接在 escape (跳脫字符)之後的單一 meta 才被關閉。
下面的例子將有助於我們對 quoting 的瞭解:
$ A=B C   # 空格鍵未被關掉,作爲 IFS 處理。
$ C: command not found. (FIXME)
$ 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 中的話,也會同樣被關閉,用 escape 亦可:
$ A=B/
> C/
>
$ echo $A
B
C
上例中,第一個 <enter> 跟第二個 <enter> 均被 escape 字符關閉了,因此也不作爲 CR 來處理,但第三個 <enter> 由於沒被跳脫,因此作爲 CR 結束 command line 。
至於 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"'   # 最外面的是單引號
"$A"
$ echo "'$A'"   # 最外面的是雙引號
'B C'
(提示:單引號及雙引號,在 quoting 中均被關?#93;了。)
--------------------------------------
在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}' 1.txt
上面的 hard quote 應好理解,就是將原本的 {、<space>、$(注三)、} 這幾個 shell meta 關閉,避免掉在 shell 中遭到處理,而完整的成爲 awk 參數中的 command meta 。( 注:而其中的$0是awk內建的field number,而非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 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 中
或許,你能舉出更多的方案呢.... ^_^

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章