一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

【Bash命令行處理】[詳解]...

 kakaxi 2008-12-18
我看很多兄弟寫腳本或命令時(shí)出現(xiàn)錯(cuò)誤的主要原因,是因?yàn)椴涣私鈈ash的命令行處理。我在這里總結(jié)了一下,大家可以參考一下。其中也涉及到雙引號(hào),單引號(hào)以及eval的技巧,我會(huì)一一講述。

代碼:
+-------------+ 單引號(hào) |------------------------->| |--------------------------| | ----------------------->| 1.分隔成記號(hào)|---- ---------------| | | | ------------------->| | 雙引號(hào) | | | | | +-------------+ | | | | | || | | | | |讀取下一個(gè)命令 \/ | | | | | +-------------------------------------------+ | | | | | | 2. | | | | | ------| 檢驗(yàn)第一個(gè)記號(hào) | | | | | |開放的關(guān)鍵字 其他關(guān)鍵字 | | | | | | 非關(guān)鍵字 | | | | | +-------------------------------------------+ | | | | || | | | | \/ | | | | +-----------------------------+ | | | | 擴(kuò)展別名 | 3. 檢驗(yàn)第一個(gè)記號(hào) | | | | |------------| 別名 | | | | | 不是別名 | | | | +-----------------------------+ | | | || | | | \/ | | | +--------------+ | | | | 4.大括號(hào)擴(kuò)展 | | | | +--------------+ | | | || | | | \/ | | | +--------------+ | | | | 5.~符號(hào)擴(kuò)展 | | | | +--------------+ | | | || | | | \/ | | | +--------------+ 雙引號(hào) | | | | 6.參數(shù)擴(kuò)展 |<-----------------| | | +--------------+ | | || | | \/ | | +------------------------------+ | | | 7.命令替換(嵌套命令行處理) | | | +------------------------------+ | | || | | \/ | | +--------------+ 雙引號(hào) | | | 8.算術(shù)擴(kuò)展 |------------------| | | +--------------+ | | | || | | | \/ | | | +--------------+ | | | | 9.單詞分割 | | | | +--------------+ | | | || | | | \/ | | | +--------------+ | | | | 10.路徑名擴(kuò)展| | | | +--------------+ | | | || | | | \/ | | | +----------------------------------------+ | | | | 11.命令查尋:函數(shù),內(nèi)置命令,可執(zhí)行文件|<---|-----| | +----------------------------------------+ | || | \/ |將參數(shù)帶入下一個(gè)命令 +-------------+ |----------eval--------------| 12.運(yùn)行命令 | +-------------+
Shell從標(biāo)準(zhǔn)輸入或腳本中讀取的每行稱為一個(gè)管道行,它包含一個(gè)或多個(gè)由0個(gè)或多個(gè)管道字符(|)分隔的命令。對(duì)每一個(gè)管道行,進(jìn)行12個(gè)步驟的處理。
結(jié)合上面的插圖,這里給出命令行的12個(gè)步驟。

1. 將命令行分成由固定元字符集分隔的記號(hào)
SPACE, TAB, NEWLINE, ; , (, ), <, >, |, &
記號(hào)類型包括單詞,關(guān)鍵字,I/O重定向符和分號(hào)。

2.檢測(cè)每個(gè)命令的第一個(gè)記號(hào),查看是否為不帶引號(hào)或反斜線的關(guān)鍵字。如果是一個(gè)開放 的關(guān)鍵字,如if和其他控制結(jié)構(gòu)起始字符串,function,{或(,則命令實(shí)際上為一復(fù)合命令。shell在內(nèi)部對(duì)復(fù)合命令進(jìn)行處理,讀取下一個(gè)命 令,并重復(fù)這一過程。如果關(guān)鍵字不是復(fù)合命令起始字符串(如then等一個(gè)控制結(jié)構(gòu)中間出現(xiàn)的關(guān)鍵字),則給出語(yǔ)法錯(cuò)誤信號(hào)。

3.依據(jù)別名列表檢查每個(gè)命令的第一個(gè)關(guān)鍵字。如果找到相應(yīng)匹配,則替換其別名定義,并退回第一步;否則進(jìn)入第4步。該策略允許遞歸別名,還允許定義關(guān)鍵字別名。如alias procedure=function

4.執(zhí)行大括號(hào)擴(kuò)展,例如a{b,c}變成ab ac

5.如果~位于單詞開頭,用$HOME替換~。使用usr的主目錄替換~user。

6.對(duì)任何以符號(hào)$開頭的表達(dá)式執(zhí)行參數(shù)(變量)替換

7.對(duì)形式$(string)的表達(dá)式進(jìn)行命令替換
這里是嵌套的命令行處理。

8.計(jì)算形式為$((string))的算術(shù)表達(dá)式

9.把行的參數(shù),命令和算術(shù)替換部分再次分成單詞,這次它使用$IFS中的字符做分割符而不是步驟1的元字符集。

10.對(duì)出現(xiàn)*, ?, [ / ]對(duì)執(zhí)行路徑名擴(kuò)展,也稱為通配符擴(kuò)展

11. 按命令優(yōu)先級(jí)表(跳過別名),進(jìn)行命令查尋

12.設(shè)置完I/O重定向和其他操作后執(zhí)行該命令。


關(guān)于引用
1. 單引號(hào)跳過了前10個(gè)步驟,不能在單引號(hào)里放單引號(hào)
2. 雙引號(hào)跳過了步驟1~5,步驟9~10,也就是說,只處理6~8個(gè)步驟。
也就是說,雙引號(hào)忽略了管道字符,別名,~替換,通配符擴(kuò)展,和通過分隔符分裂成單詞。
雙引號(hào)里的單引號(hào)沒有作用,但雙引號(hào)允許參數(shù)替換,命令替換和算術(shù)表達(dá)式求值??梢栽陔p引號(hào)里包含雙引號(hào),方式是加上轉(zhuǎn)義符"\",還必須轉(zhuǎn)義$, `, \。


eval
eval的作用是再次執(zhí)行命令行處理,也就是說,對(duì)一個(gè)命令行,執(zhí)行兩次命令行處理。
這個(gè)命令要用好,就要費(fèi)一定的功夫。我舉兩個(gè)例子,拋磚引玉。
例子1:

用eval技巧實(shí)現(xiàn)shell的控制結(jié)構(gòu)for。

代碼:
[root@home root]# cat myscript1 #!/bin/sh evalit(){ if [ $cnt = 1 ];then eval $@ return else let cnt=cnt-1 evalit $@ fi eval $@ } cnt=$1 echo $cnt | egrep "^[1-9][0-9]*$" >/dev/null if [ $? -eq 0 ]; then shift evalit $@ else echo 'ERROR!!! Check your input!' fi [root@home root]# ./myscript1 3 hostname home home home [root@home root]# ./myscript1 5 id |cut -f1 -d' ' uid=0(root) uid=0(root) uid=0(root) uid=0(root) uid=0(root)
注意,bash里有兩個(gè)很特殊的變量,它們保存了參數(shù)列表。
$*,保存了以$IFS指定的分割符所分割的字符串組。
$@,原樣保存了參數(shù)列表,也就是"$1""$2"...

這里我使用了函數(shù)遞歸以及eval實(shí)現(xiàn)了for結(jié)構(gòu)。
當(dāng)執(zhí)行eval $@時(shí),它經(jīng)歷了步驟如下:
第1步,分割成eval $@
第6步,擴(kuò)展$@為hostname
第11步,找到內(nèi)置命令eval
重復(fù)一次命令行處理,第11步,找到hostname命令,執(zhí)行。

注意:也許有人想當(dāng)然地認(rèn)為,何必用eval呢?直接$@來執(zhí)行命令就可以了嘛。
錯(cuò)誤!這里給個(gè)典型的例子大家看看。
代碼:
[root@home root]# a="id | cut -f1 -d' '" [root@home root]# $a id:無效選項(xiàng) -- f 請(qǐng)嘗試執(zhí)行‘id --help’來獲取更多信息。 [root@home root]# eval $a uid=0(root)
如果命令行復(fù)雜的話(包括管道或者其他字符),直接執(zhí)行$a字符串的內(nèi)容就會(huì)出錯(cuò)。分析如下。
$a的處理位于第6步──參數(shù)擴(kuò)展,也就是說,跳過了管道分析,于是"|", "cut", "-f1", "-d"都變成了id命令的參數(shù),當(dāng)然就出錯(cuò)啦。
但使用了eval,它把第一遍命令行處理所得的"id", "|", "cut", "-f1", "-d"這些字符串再次進(jìn)行命令行處理,這次就能正確分析其中的管道了。
總而言之,要保證你的命令或腳本設(shè)計(jì)能正確通過命令行處理,跳過任意一步,都可能造成意料外的錯(cuò)誤!


例子2:
設(shè)置系統(tǒng)的ls色彩顯示
代碼:
eval $(dircolors -b /etc/dircolors)
eval語(yǔ)句通知shell接受eval參數(shù),并再次通過命令行處理的所有步驟運(yùn)行它們。
它使你可以編寫腳本隨意創(chuàng)建命令字符串,然后把它們傳遞給shell執(zhí)行;
$()是命令替換,返回命令的輸出字符串。
其中dircolors命令根據(jù)/etc/dircolors配置文件生成設(shè)置環(huán)境變量LS_COLORS的bash代碼,內(nèi)容如下
代碼:
[root@localhost root]# dircolors -b > tmp [root@localhost root]# cat tmp LS_COLORS='no=00:fi=00:di=01;34:ln=01; ...... export LS_COLORS #這里我沒有指定配置文件,所以dircolors按預(yù)置數(shù)據(jù)庫(kù)生成代碼。 其輸出被eval命令傳遞給shell執(zhí)行。
eval是對(duì)Bash Shell命令行處理規(guī)則的靈活應(yīng)用,進(jìn)而構(gòu)造"智能"命令實(shí)現(xiàn)復(fù)雜的功能。
上面提及的命令是eval其中一個(gè)很普通的應(yīng)用,它重復(fù)了1次命令行參數(shù)傳遞過程,純粹地執(zhí)行命令的命令。
其實(shí)它是bash的難點(diǎn),是高級(jí)bash程序員的必修之技。

命令優(yōu)先級(jí)表
1.別名
2.關(guān)鍵字
3.函數(shù)
4.內(nèi)置命令
5.腳本或可執(zhí)行程序($PATH)


鑒于一些學(xué)習(xí)中會(huì)遇到的困惑,我再給出一些有趣的命令。
command builtin enable
上面的命令行提及過,第11步會(huì)進(jìn)行命令查找,那它的具體過程如何呢?
它的默認(rèn)查找次序?yàn)楹瘮?shù),內(nèi)部命令,腳本和可執(zhí)行代碼。我們往往要在實(shí)際編程中跳過一些查找項(xiàng)以滿足一定的功能需求。這時(shí)候就要用到這三個(gè)命令來施展魔法~~
command
跳過別名和函數(shù)的查找,換句話說,它只查找內(nèi)部命令以及搜索路徑中找到的腳本或可執(zhí)行程序。
這里舉個(gè)有趣的例子。
代碼:
[root@home root]# type -all pwd pwd is a shell builtin pwd is /bin/pwd [root@home root]# cat myscript2 #!/bin/sh pwd(){ echo "This is the current directory." command pwd } pwd [root@home root]# ./myscript2 This is the current directory. /root
我用pwd()函數(shù)取代了內(nèi)置命令pwd以及外部命令/bin/pwd,然后在腳本里執(zhí)行內(nèi)置命令pwd。在這里我們?yōu)槭裁匆胏ommand呢?是為了避免函數(shù)陷入遞歸循環(huán),因?yàn)楹瘮?shù)名與內(nèi)置命令同名,而函數(shù)的優(yōu)先級(jí)比內(nèi)置命令高。

builtin
顧名思義,它只查找內(nèi)置命令。這個(gè)命令很簡(jiǎn)單,就不多說了。

enable
與builtin相反,它屏蔽一個(gè)內(nèi)置命令,允許運(yùn)行一個(gè)shell腳本或同名的可執(zhí)行代碼而無須給出完全路徑名。
舉個(gè)例子吧。
pwd命令有兩個(gè),一個(gè)是shell內(nèi)置的,一個(gè)是可執(zhí)行程序。
當(dāng)執(zhí)行一些奇怪的路徑名后,shell內(nèi)置的pwd會(huì)打印出"錯(cuò)誤信息",但外部的pwd會(huì)打印出當(dāng)前目錄的"原來面目"。請(qǐng)看下面:
代碼:
[root@home root]# cd // [root@home //]# pwd // [root@home //]# type -all pwd pwd is a shell builtin pwd is /bin/pwd [root@home //]# /bin/pwd / [root@home //]# enable -n pwd [root@home //]# pwd /
這樣,用enable -n屏蔽內(nèi)置pwd命令后,就可以用外部pwd打印出正確的路徑名了。

Bash博大精深,希望大家好好學(xué)習(xí)。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    婷婷基地五月激情五月| 日本精品免费在线观看| 丝袜视频日本成人午夜视频| 在线观看免费无遮挡大尺度视频| 韩日黄片在线免费观看| 在线观看免费午夜福利| 风间中文字幕亚洲一区| 国产日产欧美精品视频| 黄色在线免费高清观看| 日韩精品一级一区二区| 国产精品尹人香蕉综合网 | 久久99青青精品免费观看| 国产精品一区二区视频| 少妇熟女精品一区二区三区| 色偷偷偷拍视频在线观看| 日本人妻中出在线观看| 国产精品超碰在线观看| 欧美高潮喷吹一区二区| 国产精品二区三区免费播放心| 青青操精品视频在线观看| 亚洲熟女乱色一区二区三区| 亚洲国产性感美女视频| 激情综合网俺也狠狠地| 日本淫片一区二区三区| 东京热加勒比一区二区三区| 儿媳妇的诱惑中文字幕| 这里只有九九热精品视频| 国产一区二区三区不卡| 在线观看视频日韩成人| 日韩三极片在线免费播放| 99久久精品国产麻豆| 久久精品国产第一区二区三区| 深夜视频成人在线观看| 性欧美唯美尤物另类视频| 欧美胖熟妇一区二区三区| 一区二区日本一区二区欧美| 国产欧美另类激情久久久| 久久精品国产在热久久| 一区二区三区日本高清| 欧美日韩亚洲国产av| 日韩人妻一区二区欧美|