亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
12下一頁
最近訪問板塊 發(fā)新帖
查看: 21077 | 回復(fù): 13
打印 上一主題 下一主題

shell歷險之——引用的迷途 [復(fù)制鏈接]

論壇徽章:
1
榮譽會員
日期:2011-11-23 16:44:17
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2006-01-10 18:57 |只看該作者 |倒序瀏覽
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:
  1. $ echo \\
  2. \
  3. $ echo "\\"
  4. \
  5. $ echo '\'
  6. \
復(fù)制代碼

第一個echo,因為\是元字符,所以必須對它進行轉(zhuǎn)義,所以我們必須用兩個\。
第二個echo,因為""是弱引用,其中的\仍然是特殊字符,所以同樣必須轉(zhuǎn)義。
第三個echo,''是強引用,\在單引號之中是普通字符,這樣就不用再轉(zhuǎn)義了,所以只用一個\。

OK,假如我們要輸出連續(xù)兩個\,怎樣呢?看一下:
  1. $ echo \\\\
  2. \\
  3. $ echo "\\\\"
  4. \\
  5. $ echo '\\'
  6. \\
復(fù)制代碼

嗯,好像沒有什么奇怪的事發(fā)生,我們簡單地使用雙倍的\就搞定了。

那再讓我們用ksh來試試來做同樣的事:
  1. $ echo \\
  2. \
  3. $ echo "\\"
  4. \
  5. $ echo '\'
  6. \
復(fù)制代碼

這個容易,簡單的重復(fù)罷了。再來兩個\:
  1. $ echo \\\\
  2. \
  3. $ echo "\\\\"
  4. \
  5. $ echo '\\'
  6. \
復(fù)制代碼

等等,怎么搞的?為什么只輸出了一個\?
再加一個\會如何?
  1. $ echo \\\\\
  2. >
  3. \
  4. $ echo \\\\\\
  5. \\
  6. $ echo "\\\\\"
  7. >
  8. \
  9. $ echo "\\\\\\"
  10. \\
  11. $ echo '\\'
  12. \\
復(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個\,......真是又臭又長!
  1. 輸出        命令行需要\的個數(shù)
  2. \        2/4
  3. \\       6/8
  4. \\\      10/12
  5. \\\\     14/16
  6. \\\\\   18/20
  7. ...       ...
  8. n個\    4n-2/4n
復(fù)制代碼

厭倦了嗎?其實ksh下除了用',還有其它方法剪斷這“懶婆娘的裹腳布”。竅門就在于echo命令的-E選項:
  1. $ echo -E \\
  2. \
  3. $ echo -E \\\\
  4. \\
  5. $ echo -E \\\\\\
  6. \\\
復(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ù)時。讓我們看下面這個簡單的例子:
  1. $ set -x
  2. $ echo \\\\
  3. + echo \\
  4. \
復(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好像工作得不好:
  1. $echo C:\\tmp | sed 's/\\/&\\/'
  2. C:        mp

  3. $echo 'C:\abc'|sed 's/\\/\\\\/'
  4. 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 編輯 ]

評分

參與人數(shù) 1可用積分 +3 收起 理由
waker + 3

查看全部評分

論壇徽章:
8
摩羯座
日期:2014-11-26 18:59:452015亞冠之浦和紅鉆
日期:2015-06-23 19:10:532015亞冠之西悉尼流浪者
日期:2015-08-21 08:40:5815-16賽季CBA聯(lián)賽之山東
日期:2016-01-31 18:25:0515-16賽季CBA聯(lián)賽之四川
日期:2016-02-16 16:08:30程序設(shè)計版塊每日發(fā)帖之星
日期:2016-06-29 06:20:002017金雞報曉
日期:2017-01-10 15:19:5615-16賽季CBA聯(lián)賽之佛山
日期:2017-02-27 20:41:19
2 [報告]
發(fā)表于 2006-01-11 09:01 |只看該作者
精華里有這樣的討論吧?
建議加上一句總結(jié): 各shell版本中內(nèi)置echo命令的默認選項是不同的

論壇徽章:
0
3 [報告]
發(fā)表于 2006-01-11 11:39 |只看該作者
大開眼界啊。。。

論壇徽章:
1
榮譽會員
日期:2011-11-23 16:44:17
4 [報告]
發(fā)表于 2006-01-11 11:55 |只看該作者
下篇:命令替換 -- 另一種引用?

命令替換(command substitution),是指在命令行獲取另一個命令的標準輸出,換句話說,它是將一個命令的標準輸出代換到另一個命令的命令行。在bsh/ksh/bash和csh中的語法都是`command`。注意這里的`是“反引號”(鍵盤上位于1鍵的左邊)。例如:
  1. /root#echo we are now in `pwd`
復(fù)制代碼

shell會將pwd命令的輸出替換`pwd`,然后打印出we are now in /root

在ksh和bash中除了可以使用上面的語法外,又引入了一種新的語法,$(command)。于是上面的例子可以改寫為下面等價的形式:
  1. \root#echo we are now in $(pwd)
復(fù)制代碼

在ksh/bash環(huán)境下,使用$()顯然比``優(yōu)越,這是因為:
其一,前者更易讀,不會產(chǎn)生歧義。而反引號`常常被初學(xué)者當成單引號';
其二,前者嵌套時更簡單,直接使用就行。而后者嵌套時內(nèi)部的反引號必須用\轉(zhuǎn)義;
其三,它們對反斜杠\的處理不一樣,在$()中可以減少轉(zhuǎn)義的麻煩。而這一點與第二點是前因后果的關(guān)系。正是因為$()嵌套時不需轉(zhuǎn)義,所以\在$()中就不需要作為一個特殊字符了。而``中的\必須是特殊字符,否則就無法嵌套使用了。

那么我們是否可以完全拋棄``的語法,只用$()就好了呢?這在大多數(shù)環(huán)境下是可行的,但如果過分強調(diào)這個的話,我認為還是太理想化了。事實上``還是有它存在的理由的,因為它的兼容性最好,在bsh/ksh/bash/csh統(tǒng)統(tǒng)可以執(zhí)行。在大部分的傳統(tǒng)unix上是沒有安裝bash的,ksh是不是都有安裝我不能確定(100%正宗的ksh好像是專有軟件),還有在一些嵌入式的linux或者高度裁剪的linux上會沒有安裝bash或者ksh。那么在這些環(huán)境下進行shell編程時我們就可能不得不使用最古老的bourne shell語法,這時優(yōu)秀的$()語法就可能完全派不上用場。

扯遠了,回到我們的主題?疾烀钐鎿Q的執(zhí)行機制,``或$()里面的內(nèi)容原則上應(yīng)該作為一個整體傳遞,交給子shell執(zhí)行。所以其中的大部分字符在傳遞給子shell之前都是普通字符。那么實際上它們在本來命令替換的功能之外似乎也起到了一種引用的效果(也算是一種副產(chǎn)品吧),所以我們不妨把它看作上篇里面講到的三種引用之外的另一種引用形式。于是我們自然會問一個問題,在這兩種“引用”中有沒有例外的特殊字符呢?當然會有,據(jù)我目前所知(不全面的地方歡迎大家指正):
``中的特殊字符有美元符$,反斜杠 \,雙引號 ",單引號',還有自身`。
$()中的特殊字符有美元符$, 雙引號"和單引號'。

既然命令替換可以看作是一種特殊的引用,我們不妨拿上篇里反斜杠的例子再來研究一下。假定我們要用兩次echo,并且要做一次命令替換。先來看比較典型的ksh:
  1. $ echo `echo \\\\`
  2. \
復(fù)制代碼

我們先來簡單解釋一下這個命令的處理過程。
第一步,shell處理整個命令行,由于``中的\是特殊字符,所以處理之后傳給內(nèi)部的echo的參數(shù)就變成了\\;
第二步,在子shell中執(zhí)行echo \\,因為ksh的echo缺省處理轉(zhuǎn)義序列,所以\在echo看來還是特殊字符,于是內(nèi)部echo輸出一個\;
第三步,將內(nèi)部echo輸出的\代入外部的echo的命令行,執(zhí)行echo '\',最終輸出一個\。

現(xiàn)在請大家猜一猜,ksh下為了要輸出兩個\,我們需要多少個\在命令行呢?大膽一點,使勁猜!
答案是20個(在bsh下也差不多,是18個)!
  1. $ echo `echo \\\\\\\\\\\\\\\\\\\\`
  2. \\
復(fù)制代碼

吃驚嗎?你會說:“這太離譜了!這條裹腳布比前面那條長了幾倍!”是的,太離譜了,難怪有人把\(英文為backslash)的自身冗長又似乎沒有規(guī)律可循的轉(zhuǎn)義叫作:“backslashit!”;-D。不過在抱怨過后還是讓我們來看看有什么方法來簡化一下吧。
ksh下:
第一件武器:強引用。防止在第一次命令行處理時解釋\。
  1. $ echo `echo '\\\\\\\\\\'`
  2. \\
復(fù)制代碼

好刀!不錯,10個\就夠用了!

第二件武器:echo的-E選項。防止echo解釋\。
  1. $ echo -E `echo -E '\\\\'`
  2. \\
復(fù)制代碼

連環(huán)雙刀!只剩4個\了。

終極武器:$()。防止執(zhí)行內(nèi)部的echo時在子shell的命令行解釋\。
  1. $ echo -E $(echo -E '\\')
  2. \\
復(fù)制代碼

枝枝杈杈砍精光,剩下兩個對一雙!這次終于達到最簡了。

其他的shell情況如何呢?
bsh不支持$(...)的語法,`...`的情況與ksh類似,只是echo的處理與ksh稍有一點不同。
bash的情況類似,注意echo缺省不解釋轉(zhuǎn)移序列(等價于ksh的echo -E)。
tcsh不支持$(...)語法,`...`中情況也稍簡單些:
  1. $ echo $0
  2. csh
  3. $ echo `echo \\`
  4. \
  5. $echo `echo \\\\`
  6. \\
  7. $ echo `echo '\\'`
  8. \\
復(fù)制代碼

tcsh與這個例子有關(guān)的引用方面的特點是:
單引號和雙引號中的\為普通字符。
echo中\(zhòng)默認為普通字符。
``中\(zhòng)為特殊字符。
詳細內(nèi)容請參看csh的相關(guān)文檔。

最后,讓我們繼續(xù)討論上面那個dos路徑的實際問題作為一個練習,為了敘述方便,對原問題略加改動:
#!/bin/ksh
dospath='c:\tmp'
escaped=`echo $dospath|sed 's/\\/&&/'`
echo $escaped

在ksh下執(zhí)行上面的腳本報錯:
sed:-e 表達式 #1,字符 7:unterminated `s' command
你能找出所有的錯誤嗎?
根據(jù)出錯信息,首先容易知道sed的命令行有問題。對了,哪里有問題?還是經(jīng)常搗亂的\吧?又對了,怎樣修改呢?
兼容性最好的語法:
  1. escaped=`echo $dospath|sed 's/\\\\/&&/'`
復(fù)制代碼

OK,執(zhí)行通過!

再來,最優(yōu)雅的的語法:
  1. escaped=$(echo $dospath|sed 's/\\/&&/')
復(fù)制代碼

很好!也通過。

重新執(zhí)行腳本,輸出:
  1. c: mp
復(fù)制代碼

還不對,那么哪里還有錯誤呢?嗯,對了,是echo的問題。如何修改?
  1. escaped=`echo -E $dospath|sed 's/\\\\/&&/'`
復(fù)制代碼

不錯。再次執(zhí)行腳本,輸出:
  1. c:\tmp
復(fù)制代碼

仍然不是我們想要的結(jié)果。哪里還有問題呢?對了,別忘了最后一個echo!
  1. echo -E $escaped
復(fù)制代碼


再次執(zhí)行腳本,輸出:
  1. c:\\tmp
復(fù)制代碼

大功告成!

OK!通過這上下兩篇關(guān)于引用和反斜杠\的討論,相信您對shell的引用和轉(zhuǎn)義有了更加深入的理解。讓我們小結(jié)一下,幫助您強化記憶:

關(guān)于引用:
三種公認的引用方式:
  1. 強引用('...'),特殊字符:單引號'自身
  2. 弱引用("..."),特殊字符:雙引號"自身,反斜杠\,美元符$,還有反引號`
  3. 轉(zhuǎn)義(\.),沒有例外,連\自身也可以被轉(zhuǎn)義。
復(fù)制代碼

woodie自己加入的兩種“類引用”方式(一家之言,姑妄言之,姑妄聽之吧。歡迎拍磚!^_^):
  1. ``,bsh/ksh/bash/csh中可用,特殊字符:反引號自身`,美元符$,反斜杠\,還有單、雙引號'和”。
  2. $(),ksh/bash中可用,特殊字符有美元符$,還有單、雙引號'和”。
復(fù)制代碼

關(guān)于echo:
  1. bsh:解釋轉(zhuǎn)義字符序列,且不能關(guān)掉
  2. ksh:缺省解釋轉(zhuǎn)義字符序列,可以用-E選項關(guān)掉
  3. bash:缺省不解釋轉(zhuǎn)義字符序列,可以用-e選項打開
復(fù)制代碼


說明,我的測試環(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 編輯 ]

論壇徽章:
0
5 [報告]
發(fā)表于 2006-01-11 11:58 |只看該作者
支持一把,樓主寫的不錯,現(xiàn)在工作時間,來不及細看,RSS訂閱先. 這個應(yīng)該是和不同的shell對 escape鍵"\"的解釋有關(guān)

論壇徽章:
1
榮譽版主
日期:2011-11-23 16:44:17
6 [報告]
發(fā)表于 2006-01-11 14:00 |只看該作者
好刀!!

論壇徽章:
1
榮譽會員
日期:2011-11-23 16:44:17
7 [報告]
發(fā)表于 2006-01-11 15:24 |只看該作者
向網(wǎng)兄學(xué)習!我只是把自己學(xué)習過程中的一點點小小心得寫下來與大家分享罷了。
以網(wǎng)兄的十三問為榜樣,我盡力把它寫的生動些,不過實在力有不逮,網(wǎng)兄見笑了!

論壇徽章:
1
榮譽會員
日期:2011-11-23 16:44:17
8 [報告]
發(fā)表于 2006-01-13 10:15 |只看該作者
又有網(wǎng)友問起與這個帖子相關(guān)的問題,我很受鼓舞!也許小弟的帖子起碼對一部分網(wǎng)友還有點參考作用吧,所以我就厚著臉皮自己頂起來。

論壇徽章:
1
榮譽會員
日期:2011-11-23 16:44:17
9 [報告]
發(fā)表于 2006-01-13 10:32 |只看該作者
多謝mocou版主加精鼓勵!我在CU學(xué)到很多,以后有時間多總結(jié)點自己的心得,與大家一起切磋。

論壇徽章:
0
10 [報告]
發(fā)表于 2006-01-13 13:58 |只看該作者
好文章
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP