亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区
Chinaunix
標(biāo)題:
shell歷險(xiǎn)之——引用的迷途
[打印本頁]
作者:
woodie
時(shí)間:
2006-01-10 18:57
標(biāo)題:
shell歷險(xiǎn)之——引用的迷途
shell歷險(xiǎn)之——引用的迷途
上篇:引用,奇怪的反斜線
我們知道在shell中有兩類字符,一類是普通字符(literal),在shell中沒有任何特殊意義;另一類是所謂“元字符”(meta),在shell中有特殊的含義或用法。
當(dāng)我們需要去掉元字符的特殊含義而恢復(fù)其字面意義時(shí)就必須使用“引用”(quoting)。通常有三種引用方式,他們是轉(zhuǎn)義(Escape,使用反斜杠字符\,即backslash),強(qiáng)引用(使用單引號(hào)',即single quote)和弱引用(使用雙引號(hào)", 即double quote)。
轉(zhuǎn)義:是用反斜杠放在需要轉(zhuǎn)義的一個(gè)字符前,表示那個(gè)字符要看作一個(gè)普通字符。
強(qiáng)引用:是用單引號(hào)把要轉(zhuǎn)義的字符串括起來,其中任何字符都看作普通字符,除了單引號(hào)自身。所以你無法在兩個(gè)單引號(hào)之間包含單引號(hào),用\轉(zhuǎn)義也不行。
弱引用:是用雙引號(hào)把要轉(zhuǎn)義的字符串括起來,除了雙引號(hào)"本身,其中的大部分字符都看作普通字符。例外的還有\(zhòng),$,`三個(gè)特殊字符。因?yàn)閈在""中是特殊字符,所以你可以在其中包含"本身,前提是必須轉(zhuǎn)義。$是特殊字符,這表示你可以使用變量$var/${var}及其它,在ksh/bash中可以引用算術(shù)表達(dá)式的結(jié)果$((...)),還可以作命令替換$()。由于`是特殊字符在bsh中也可以作命令替換,但只能使用`...`的語法(這個(gè)在ksh/bash中也可以使用)。
關(guān)于三種引用,網(wǎng)中人的“shell十三問”之第四問已經(jīng)講得很清楚了,我這里就不重復(fù)了。
今天我們單獨(dú)研究一下反斜線\。這是一個(gè)有魔力的字符,它可以用來對(duì)任何字符轉(zhuǎn)義,也包括它自己。但是在不同的shell實(shí)現(xiàn)中它的表現(xiàn)似乎不盡相同,有時(shí)結(jié)果讓你會(huì)大吃一驚。
先來看一個(gè)簡(jiǎn)單的例子,假定我們要輸出單獨(dú)一個(gè)\,先用bash:
$ echo \\
\
$ echo "\\"
\
$ echo '\'
\
復(fù)制代碼
第一個(gè)echo,因?yàn)閈是元字符,所以必須對(duì)它進(jìn)行轉(zhuǎn)義,所以我們必須用兩個(gè)\。
第二個(gè)echo,因?yàn)?quot;"是弱引用,其中的\仍然是特殊字符,所以同樣必須轉(zhuǎn)義。
第三個(gè)echo,''是強(qiáng)引用,\在單引號(hào)之中是普通字符,這樣就不用再轉(zhuǎn)義了,所以只用一個(gè)\。
OK,假如我們要輸出連續(xù)兩個(gè)\,怎樣呢?看一下:
$ echo \\\\
\\
$ echo "\\\\"
\\
$ echo '\\'
\\
復(fù)制代碼
嗯,好像沒有什么奇怪的事發(fā)生,我們簡(jiǎn)單地使用雙倍的\就搞定了。
那再讓我們用ksh來試試來做同樣的事:
$ echo \\
\
$ echo "\\"
\
$ echo '\'
\
復(fù)制代碼
這個(gè)容易,簡(jiǎn)單的重復(fù)罷了。再來兩個(gè)\:
$ echo \\\\
\
$ echo "\\\\"
\
$ echo '\\'
\
復(fù)制代碼
等等,怎么搞的?為什么只輸出了一個(gè)\?
再加一個(gè)\會(huì)如何?
$ echo \\\\\
>
\
$ echo \\\\\\
\\
$ echo "\\\\\"
>
\
$ echo "\\\\\\"
\\
$ echo '\\'
\\
復(fù)制代碼
第一個(gè)echo沒有立即執(zhí)行,ksh給出了一個(gè)>(PS2提示符),等待我們繼續(xù)輸入,回車后echo仍然只輸出了一個(gè)\。
第二個(gè)echo后面是六個(gè)\,呼~,這回終于輸出兩個(gè)\了。
雙引號(hào)的情形也是類似,我們?nèi)匀恍枰鶄(gè)\。
第五個(gè)echo,好在單引號(hào)的結(jié)果還算不錯(cuò),只要兩個(gè)\就行了。
你可以繼續(xù)做這個(gè)試驗(yàn),最后會(huì)發(fā)現(xiàn)在不用單引號(hào)時(shí),我們需要2個(gè)或4個(gè)\輸出1個(gè)\,需要6個(gè)或8個(gè)\輸出2個(gè)\,10個(gè)或12個(gè)\來輸出3個(gè)\,......真是又臭又長(zhǎng)!
輸出 命令行需要\的個(gè)數(shù)
\ 2/4
\\ 6/8
\\\ 10/12
\\\\ 14/16
\\\\\ 18/20
... ...
n個(gè)\ 4n-2/4n
復(fù)制代碼
厭倦了嗎?其實(shí)ksh下除了用',還有其它方法剪斷這“懶婆娘的裹腳布”。竅門就在于echo命令的-E選項(xiàng):
$ echo -E \\
\
$ echo -E \\\\
\\
$ echo -E \\\\\\
\\\
復(fù)制代碼
很好!這樣與bash下的情況就一樣了,-E選項(xiàng)是不是很神奇呀!為什么呢?
原來bash和ksh的echo命令缺省的表現(xiàn)是不同的。我們知道echo命令可以接受一些轉(zhuǎn)義字符序列來表示特殊的字符,如\n表示換行,\a表示蜂鳴,\t表示水平制表符等等。顯然在解釋轉(zhuǎn)義序列時(shí)\是一個(gè)特殊字符。
在bash下echo缺省的設(shè)置是不解釋這些轉(zhuǎn)義序列,為了告訴它解釋轉(zhuǎn)義序列我們必須使用-e選項(xiàng)。
而在ksh下echo的缺省設(shè)置就會(huì)解釋這些轉(zhuǎn)義序列,我們可以用-E選項(xiàng)讓它不解釋轉(zhuǎn)義序列。所以ksh下在不使用-E選項(xiàng)時(shí)實(shí)際上會(huì)發(fā)生兩次轉(zhuǎn)義的過程,第一次發(fā)生在ksh處理命令行時(shí),第二次發(fā)生在echo命令處理它的參數(shù)時(shí)。讓我們看下面這個(gè)簡(jiǎn)單的例子:
$ set -x
$ echo \\\\
+ echo \\
\
復(fù)制代碼
先用set -x讓ksh顯示命令行處理的結(jié)果,我們看到,第一個(gè)\轉(zhuǎn)義第二個(gè)\,去掉它的特殊含義,同樣第三個(gè)\轉(zhuǎn)義第四個(gè)\去掉它的特殊含義,這樣命令行處理完畢以后傳給echo的參數(shù)是\\。echo然后將\\解釋成了\并輸出。于是我們只得到一個(gè)\。
bsh中echo的缺省表現(xiàn)與ksh中類似,解釋轉(zhuǎn)義序列,不過可惜無法關(guān)掉這一功能。
我們還是可以使用外部命令來不解釋轉(zhuǎn)義序列原樣輸出,例如在linux下可以用
/bin/echo -E(可以省略)來做。
下來看一個(gè)從本論壇來的例子,提問者的意圖是將dos格式的路徑中的\變成\\,但他的shell好像工作得不好:
$echo C:\\tmp | sed 's/\\/&\\/'
C: mp
$echo 'C:\abc'|sed 's/\\/\\\\/'
C:bc
復(fù)制代碼
在看過上面我們對(duì)引用和echo的討論之后,您能為他解釋一下其中的原因嗎?
對(duì)了,這兩條命令的語法都沒有錯(cuò),不過提問者使用的shell八成是ksh(也可能是bsh,但可能性較小),問題是出在echo上。在ksh下echo默認(rèn)解釋轉(zhuǎn)義序列,所以命令行的
echo c:\\tmp部分先做命令行解釋,\\變成\,于是執(zhí)行:
echo 'c:\tmp'
而\t是一個(gè)轉(zhuǎn)義序列,它代表水平制表符,所以echo最后輸出
c:
<水平制表符>
mp
同樣
echo 'c:\abc'
會(huì)輸出
c:
<蜂鳴字符>
bc
你應(yīng)該會(huì)聽到你的終端發(fā)出“嘟”的一聲。
這下清楚了吧?echo的輸出就是錯(cuò)誤的,后面sed的替換根本就沒有匹配執(zhí)行,當(dāng)然不會(huì)有正確的結(jié)果。
上面兩個(gè)命令在bash下是正確的,為什么?
那在ksh下怎樣修改讓它正確工作呢?如果是bsh呢?改法可能不止一種,不過這個(gè)還是留給親愛的讀者您作為一個(gè)練習(xí)好了。
(未完待續(xù),請(qǐng)看下篇)
[
本帖最后由 woodie 于 2006-1-11 16:46 編輯
]
作者:
waker
時(shí)間:
2006-01-11 09:01
精華里有這樣的討論吧?
建議加上一句總結(jié): 各shell版本中內(nèi)置echo命令的默認(rèn)選項(xiàng)是不同的
作者:
dbcat
時(shí)間:
2006-01-11 11:39
大開眼界啊。。。
作者:
woodie
時(shí)間:
2006-01-11 11:55
下篇:命令替換 -- 另一種引用?
命令替換(command substitution),是指在命令行獲取另一個(gè)命令的標(biāo)準(zhǔn)輸出,換句話說,它是將一個(gè)命令的標(biāo)準(zhǔn)輸出代換到另一個(gè)命令的命令行。在bsh/ksh/bash和csh中的語法都是`command`。注意這里的`是“反引號(hào)”(鍵盤上位于1鍵的左邊)。例如:
/root#echo we are now in `pwd`
復(fù)制代碼
shell會(huì)將pwd命令的輸出替換`pwd`,然后打印出we are now in /root
在ksh和bash中除了可以使用上面的語法外,又引入了一種新的語法,$(command)。于是上面的例子可以改寫為下面等價(jià)的形式:
\root#echo we are now in $(pwd)
復(fù)制代碼
在ksh/bash環(huán)境下,使用$()顯然比``優(yōu)越,這是因?yàn)椋?br /> 其一,前者更易讀,不會(huì)產(chǎn)生歧義。而反引號(hào)`常常被初學(xué)者當(dāng)成單引號(hào)';
其二,前者嵌套時(shí)更簡(jiǎn)單,直接使用就行。而后者嵌套時(shí)內(nèi)部的反引號(hào)必須用\轉(zhuǎn)義;
其三,它們對(duì)反斜杠\的處理不一樣,在$()中可以減少轉(zhuǎn)義的麻煩。而這一點(diǎn)與第二點(diǎn)是前因后果的關(guān)系。正是因?yàn)?()嵌套時(shí)不需轉(zhuǎn)義,所以\在$()中就不需要作為一個(gè)特殊字符了。而``中的\必須是特殊字符,否則就無法嵌套使用了。
那么我們是否可以完全拋棄``的語法,只用$()就好了呢?這在大多數(shù)環(huán)境下是可行的,但如果過分強(qiáng)調(diào)這個(gè)的話,我認(rèn)為還是太理想化了。事實(shí)上``還是有它存在的理由的,因?yàn)樗募嫒菪宰詈,在bsh/ksh/bash/csh統(tǒng)統(tǒng)可以執(zhí)行。在大部分的傳統(tǒng)unix上是沒有安裝bash的,ksh是不是都有安裝我不能確定(100%正宗的ksh好像是專有軟件),還有在一些嵌入式的linux或者高度裁剪的linux上會(huì)沒有安裝bash或者ksh。那么在這些環(huán)境下進(jìn)行shell編程時(shí)我們就可能不得不使用最古老的bourne shell語法,這時(shí)優(yōu)秀的$()語法就可能完全派不上用場(chǎng)。
扯遠(yuǎn)了,回到我們的主題。考察命令替換的執(zhí)行機(jī)制,``或$()里面的內(nèi)容原則上應(yīng)該作為一個(gè)整體傳遞,交給子shell執(zhí)行。所以其中的大部分字符在傳遞給子shell之前都是普通字符。那么實(shí)際上它們?cè)诒緛砻钐鎿Q的功能之外似乎也起到了一種引用的效果(也算是一種副產(chǎn)品吧),所以我們不妨把它看作上篇里面講到的三種引用之外的另一種引用形式。于是我們自然會(huì)問一個(gè)問題,在這兩種“引用”中有沒有例外的特殊字符呢?當(dāng)然會(huì)有,據(jù)我目前所知(不全面的地方歡迎大家指正):
``中的特殊字符有美元符$,反斜杠 \,雙引號(hào) ",單引號(hào)',還有自身`。
$()中的特殊字符有美元符$, 雙引號(hào)"和單引號(hào)'。
既然命令替換可以看作是一種特殊的引用,我們不妨拿上篇里反斜杠的例子再來研究一下。假定我們要用兩次echo,并且要做一次命令替換。先來看比較典型的ksh:
$ echo `echo \\\\`
\
復(fù)制代碼
我們先來簡(jiǎn)單解釋一下這個(gè)命令的處理過程。
第一步,shell處理整個(gè)命令行,由于``中的\是特殊字符,所以處理之后傳給內(nèi)部的echo的參數(shù)就變成了\\;
第二步,在子shell中執(zhí)行echo \\,因?yàn)閗sh的echo缺省處理轉(zhuǎn)義序列,所以\在echo看來還是特殊字符,于是內(nèi)部echo輸出一個(gè)\;
第三步,將內(nèi)部echo輸出的\代入外部的echo的命令行,執(zhí)行echo '\',最終輸出一個(gè)\。
現(xiàn)在請(qǐng)大家猜一猜,ksh下為了要輸出兩個(gè)\,我們需要多少個(gè)\在命令行呢?大膽一點(diǎn),使勁猜!
答案是20個(gè)(在bsh下也差不多,是18個(gè))!
$ echo `echo \\\\\\\\\\\\\\\\\\\\`
\\
復(fù)制代碼
吃驚嗎?你會(huì)說:“這太離譜了!這條裹腳布比前面那條長(zhǎng)了幾倍!”是的,太離譜了,難怪有人把\(英文為backslash)的自身冗長(zhǎng)又似乎沒有規(guī)律可循的轉(zhuǎn)義叫作:“backslashit!”;-D。不過在抱怨過后還是讓我們來看看有什么方法來簡(jiǎn)化一下吧。
ksh下:
第一件武器:強(qiáng)引用。防止在第一次命令行處理時(shí)解釋\。
$ echo `echo '\\\\\\\\\\'`
\\
復(fù)制代碼
好刀!不錯(cuò),10個(gè)\就夠用了!
第二件武器:echo的-E選項(xiàng)。防止echo解釋\。
$ echo -E `echo -E '\\\\'`
\\
復(fù)制代碼
連環(huán)雙刀!只剩4個(gè)\了。
終極武器:$()。防止執(zhí)行內(nèi)部的echo時(shí)在子shell的命令行解釋\。
$ echo -E $(echo -E '\\')
\\
復(fù)制代碼
枝枝杈杈砍精光,剩下兩個(gè)對(duì)一雙!這次終于達(dá)到最簡(jiǎn)了。
其他的shell情況如何呢?
bsh不支持$(...)的語法,`...`的情況與ksh類似,只是echo的處理與ksh稍有一點(diǎn)不同。
bash的情況類似,注意echo缺省不解釋轉(zhuǎn)移序列(等價(jià)于ksh的echo -E)。
tcsh不支持$(...)語法,`...`中情況也稍簡(jiǎn)單些:
$ echo $0
csh
$ echo `echo \\`
\
$echo `echo \\\\`
\\
$ echo `echo '\\'`
\\
復(fù)制代碼
tcsh與這個(gè)例子有關(guān)的引用方面的特點(diǎn)是:
單引號(hào)和雙引號(hào)中的\為普通字符。
echo中\(zhòng)默認(rèn)為普通字符。
``中\(zhòng)為特殊字符。
詳細(xì)內(nèi)容請(qǐng)參看csh的相關(guān)文檔。
最后,讓我們繼續(xù)討論上面那個(gè)dos路徑的實(shí)際問題作為一個(gè)練習(xí),為了敘述方便,對(duì)原問題略加改動(dòng):
#!/bin/ksh
dospath='c:\tmp'
escaped=`echo $dospath|sed 's/\\/&&/'`
echo $escaped
在ksh下執(zhí)行上面的腳本報(bào)錯(cuò):
sed:-e 表達(dá)式 #1,字符 7:unterminated `s' command
你能找出所有的錯(cuò)誤嗎?
根據(jù)出錯(cuò)信息,首先容易知道sed的命令行有問題。對(duì)了,哪里有問題?還是經(jīng)常搗亂的\吧?又對(duì)了,怎樣修改呢?
兼容性最好的語法:
escaped=`echo $dospath|sed 's/\\\\/&&/'`
復(fù)制代碼
OK,執(zhí)行通過!
再來,最優(yōu)雅的的語法:
escaped=$(echo $dospath|sed 's/\\/&&/')
復(fù)制代碼
很好!也通過。
重新執(zhí)行腳本,輸出:
c: mp
復(fù)制代碼
還不對(duì),那么哪里還有錯(cuò)誤呢?嗯,對(duì)了,是echo的問題。如何修改?
escaped=`echo -E $dospath|sed 's/\\\\/&&/'`
復(fù)制代碼
不錯(cuò)。再次執(zhí)行腳本,輸出:
c:\tmp
復(fù)制代碼
仍然不是我們想要的結(jié)果。哪里還有問題呢?對(duì)了,別忘了最后一個(gè)echo!
echo -E $escaped
復(fù)制代碼
再次執(zhí)行腳本,輸出:
c:\\tmp
復(fù)制代碼
大功告成!
OK!通過這上下兩篇關(guān)于引用和反斜杠\的討論,相信您對(duì)shell的引用和轉(zhuǎn)義有了更加深入的理解。讓我們小結(jié)一下,幫助您強(qiáng)化記憶:
關(guān)于引用:
三種公認(rèn)的引用方式:
強(qiáng)引用('...'),特殊字符:?jiǎn)我?hào)'自身
弱引用("..."),特殊字符:雙引號(hào)"自身,反斜杠\,美元符$,還有反引號(hào)`
轉(zhuǎn)義(\.),沒有例外,連\自身也可以被轉(zhuǎn)義。
復(fù)制代碼
woodie自己加入的兩種“類引用”方式(一家之言,姑妄言之,姑妄聽之吧。歡迎拍磚!^_^):
``,bsh/ksh/bash/csh中可用,特殊字符:反引號(hào)自身`,美元符$,反斜杠\,還有單、雙引號(hào)'和”。
$(),ksh/bash中可用,特殊字符有美元符$,還有單、雙引號(hào)'和”。
復(fù)制代碼
關(guān)于echo:
bsh:解釋轉(zhuǎn)義字符序列,且不能關(guān)掉
ksh:缺省解釋轉(zhuǎn)義字符序列,可以用-E選項(xiàng)關(guān)掉
bash:缺省不解釋轉(zhuǎn)義字符序列,可以用-e選項(xiàng)打開
復(fù)制代碼
說明,我的測(cè)試環(huán)境:
Centos 4.2 x86-64
bash: 3.00.15(1)
ksh pdksh-5.2.14-30.3
bsh ash-0.3.8-20
csh tcsh-6.13-9
[
本帖最后由 woodie 于 2006-1-11 14:46 編輯
]
作者:
大螞蟻
時(shí)間:
2006-01-11 11:58
支持一把,樓主寫的不錯(cuò),現(xiàn)在工作時(shí)間,來不及細(xì)看,RSS訂閱先. 這個(gè)應(yīng)該是和不同的shell對(duì) escape鍵"\"的解釋有關(guān)
作者:
網(wǎng)中人
時(shí)間:
2006-01-11 14:00
好刀!!
作者:
woodie
時(shí)間:
2006-01-11 15:24
向網(wǎng)兄學(xué)習(xí)!我只是把自己學(xué)習(xí)過程中的一點(diǎn)點(diǎn)小小心得寫下來與大家分享罷了。
以網(wǎng)兄的十三問為榜樣,我盡力把它寫的生動(dòng)些,不過實(shí)在力有不逮,網(wǎng)兄見笑了!
作者:
woodie
時(shí)間:
2006-01-13 10:15
又有網(wǎng)友問起與這個(gè)帖子相關(guān)的問題,我很受鼓舞!也許小弟的帖子起碼對(duì)一部分網(wǎng)友還有點(diǎn)參考作用吧,所以我就厚著臉皮自己頂起來。
作者:
woodie
時(shí)間:
2006-01-13 10:32
多謝mocou版主加精鼓勵(lì)!我在CU學(xué)到很多,以后有時(shí)間多總結(jié)點(diǎn)自己的心得,與大家一起切磋。
作者:
231053469
時(shí)間:
2006-01-13 13:58
好文章
作者:
honbj
時(shí)間:
2006-06-01 10:10
[
本帖最后由 honbj 于 2006-6-1 13:40 編輯
]
作者:
源方
時(shí)間:
2006-06-01 14:39
算你狠
作者:
wstar
時(shí)間:
2008-08-20 23:24
真是好文章
作者:
welcome008
時(shí)間:
2008-08-21 00:52
我也標(biāo)記一下
歡迎光臨 Chinaunix (http://72891.cn/)
Powered by Discuz! X3.2