- 論壇徽章:
- 1
|
shell歷險之——引用的迷途
上篇:引用,奇怪的反斜線
我們知道在shell中有兩類字符,一類是普通字符(literal),在shell中沒有任何特殊意義;另一類是所謂“元字符”(meta),在shell中有特殊的含義或用法。
當我們需要去掉元字符的特殊含義而恢復(fù)其字面意義時就必須使用“引用”(quoting)。通常有三種引用方式,他們是轉(zhuǎn)義(Escape,使用反斜杠字符\,即backslash),強引用(使用單引號',即single quote)和弱引用(使用雙引號", 即double quote)。
轉(zhuǎn)義:是用反斜杠放在需要轉(zhuǎn)義的一個字符前,表示那個字符要看作一個普通字符。
強引用:是用單引號把要轉(zhuǎn)義的字符串括起來,其中任何字符都看作普通字符,除了單引號自身。所以你無法在兩個單引號之間包含單引號,用\轉(zhuǎn)義也不行。
弱引用:是用雙引號把要轉(zhuǎn)義的字符串括起來,除了雙引號"本身,其中的大部分字符都看作普通字符。例外的還有\(zhòng),$,`三個特殊字符。因為\在""中是特殊字符,所以你可以在其中包含"本身,前提是必須轉(zhuǎn)義。$是特殊字符,這表示你可以使用變量$var/${var}及其它,在ksh/bash中可以引用算術(shù)表達式的結(jié)果$((...)),還可以作命令替換$()。由于`是特殊字符在bsh中也可以作命令替換,但只能使用`...`的語法(這個在ksh/bash中也可以使用)。
關(guān)于三種引用,網(wǎng)中人的“shell十三問”之第四問已經(jīng)講得很清楚了,我這里就不重復(fù)了。
今天我們單獨研究一下反斜線\。這是一個有魔力的字符,它可以用來對任何字符轉(zhuǎn)義,也包括它自己。但是在不同的shell實現(xiàn)中它的表現(xiàn)似乎不盡相同,有時結(jié)果讓你會大吃一驚。
先來看一個簡單的例子,假定我們要輸出單獨一個\,先用bash:
- $ echo \\
- \
- $ echo "\\"
- \
- $ echo '\'
- \
復(fù)制代碼
第一個echo,因為\是元字符,所以必須對它進行轉(zhuǎn)義,所以我們必須用兩個\。
第二個echo,因為""是弱引用,其中的\仍然是特殊字符,所以同樣必須轉(zhuǎn)義。
第三個echo,''是強引用,\在單引號之中是普通字符,這樣就不用再轉(zhuǎn)義了,所以只用一個\。
OK,假如我們要輸出連續(xù)兩個\,怎樣呢?看一下:
- $ echo \\\\
- \\
- $ echo "\\\\"
- \\
- $ echo '\\'
- \\
復(fù)制代碼
嗯,好像沒有什么奇怪的事發(fā)生,我們簡單地使用雙倍的\就搞定了。
那再讓我們用ksh來試試來做同樣的事:
- $ echo \\
- \
- $ echo "\\"
- \
- $ echo '\'
- \
復(fù)制代碼
這個容易,簡單的重復(fù)罷了。再來兩個\:
- $ echo \\\\
- \
- $ echo "\\\\"
- \
- $ echo '\\'
- \
復(fù)制代碼
等等,怎么搞的?為什么只輸出了一個\?
再加一個\會如何?
- $ echo \\\\\
- >
- \
- $ echo \\\\\\
- \\
- $ echo "\\\\\"
- >
- \
- $ echo "\\\\\\"
- \\
- $ echo '\\'
- \\
復(fù)制代碼
第一個echo沒有立即執(zhí)行,ksh給出了一個>(PS2提示符),等待我們繼續(xù)輸入,回車后echo仍然只輸出了一個\。
第二個echo后面是六個\,呼~,這回終于輸出兩個\了。
雙引號的情形也是類似,我們?nèi)匀恍枰鶄\。
第五個echo,好在單引號的結(jié)果還算不錯,只要兩個\就行了。
你可以繼續(xù)做這個試驗,最后會發(fā)現(xiàn)在不用單引號時,我們需要2個或4個\輸出1個\,需要6個或8個\輸出2個\,10個或12個\來輸出3個\,......真是又臭又長!
- 輸出 命令行需要\的個數(shù)
- \ 2/4
- \\ 6/8
- \\\ 10/12
- \\\\ 14/16
- \\\\\ 18/20
- ... ...
- n個\ 4n-2/4n
復(fù)制代碼
厭倦了嗎?其實ksh下除了用',還有其它方法剪斷這“懶婆娘的裹腳布”。竅門就在于echo命令的-E選項:
- $ echo -E \\
- \
- $ echo -E \\\\
- \\
- $ echo -E \\\\\\
- \\\
復(fù)制代碼
很好!這樣與bash下的情況就一樣了,-E選項是不是很神奇呀!為什么呢?
原來bash和ksh的echo命令缺省的表現(xiàn)是不同的。我們知道echo命令可以接受一些轉(zhuǎn)義字符序列來表示特殊的字符,如\n表示換行,\a表示蜂鳴,\t表示水平制表符等等。顯然在解釋轉(zhuǎn)義序列時\是一個特殊字符。
在bash下echo缺省的設(shè)置是不解釋這些轉(zhuǎn)義序列,為了告訴它解釋轉(zhuǎn)義序列我們必須使用-e選項。
而在ksh下echo的缺省設(shè)置就會解釋這些轉(zhuǎn)義序列,我們可以用-E選項讓它不解釋轉(zhuǎn)義序列。所以ksh下在不使用-E選項時實際上會發(fā)生兩次轉(zhuǎn)義的過程,第一次發(fā)生在ksh處理命令行時,第二次發(fā)生在echo命令處理它的參數(shù)時。讓我們看下面這個簡單的例子:
- $ set -x
- $ echo \\\\
- + echo \\
- \
復(fù)制代碼
先用set -x讓ksh顯示命令行處理的結(jié)果,我們看到,第一個\轉(zhuǎn)義第二個\,去掉它的特殊含義,同樣第三個\轉(zhuǎn)義第四個\去掉它的特殊含義,這樣命令行處理完畢以后傳給echo的參數(shù)是\\。echo然后將\\解釋成了\并輸出。于是我們只得到一個\。
bsh中echo的缺省表現(xiàn)與ksh中類似,解釋轉(zhuǎn)義序列,不過可惜無法關(guān)掉這一功能。 我們還是可以使用外部命令來不解釋轉(zhuǎn)義序列原樣輸出,例如在linux下可以用
/bin/echo -E(可以省略)來做。
下來看一個從本論壇來的例子,提問者的意圖是將dos格式的路徑中的\變成\\,但他的shell好像工作得不好:
- $echo C:\\tmp | sed 's/\\/&\\/'
- C: mp
- $echo 'C:\abc'|sed 's/\\/\\\\/'
- C:bc
復(fù)制代碼
在看過上面我們對引用和echo的討論之后,您能為他解釋一下其中的原因嗎?
對了,這兩條命令的語法都沒有錯,不過提問者使用的shell八成是ksh(也可能是bsh,但可能性較小),問題是出在echo上。在ksh下echo默認解釋轉(zhuǎn)義序列,所以命令行的
echo c:\\tmp部分先做命令行解釋,\\變成\,于是執(zhí)行:
echo 'c:\tmp'
而\t是一個轉(zhuǎn)義序列,它代表水平制表符,所以echo最后輸出
c:<水平制表符>mp
同樣
echo 'c:\abc'
會輸出
c:<蜂鳴字符>bc
你應(yīng)該會聽到你的終端發(fā)出“嘟”的一聲。
這下清楚了吧?echo的輸出就是錯誤的,后面sed的替換根本就沒有匹配執(zhí)行,當然不會有正確的結(jié)果。
上面兩個命令在bash下是正確的,為什么?
那在ksh下怎樣修改讓它正確工作呢?如果是bsh呢?改法可能不止一種,不過這個還是留給親愛的讀者您作為一個練習好了。
(未完待續(xù),請看下篇)
[ 本帖最后由 woodie 于 2006-1-11 16:46 編輯 ] |
評分
-
查看全部評分
|