eval命令將會首先掃描命令行進行所有的替換,類似于C語言中的宏替換,然后再執(zhí)行命令。該命令使用于那些一次掃描無法實現(xiàn)其功能的變量。該命令對變量進行兩次掃描。這些需要進行兩次掃描的變量有時候被稱為復雜變量。
新建一個文件test將字符串”helloworld!“寫入文件中,把cat test賦值給變量word,如果我們echo word并不能的到test中的內(nèi)容;然而eval word則能顯示文件中的內(nèi)容,因為eval命令對后面的命令進行了兩次掃描,第一次將word替換為 cat test,第二次執(zhí)行cat test。
2.eval也可以用于回寫簡單變量,不一定是復雜變量。
?? ?NAME=ZONE
?? ?eval echo $NAME等價于echo $NAME
3、eval命令還可以獲取傳給shell的最后一個參數(shù)?
如果我們知道參數(shù)個數(shù),我們想要查看最后一個參數(shù)的內(nèi)容可以使用echo直接顯示,如輸入 first last兩個參數(shù)我們可以用echo?$2 來查看最后一個參數(shù);?
但是,如果我們不知道參數(shù)個數(shù)還想查看最后一個參數(shù)內(nèi)容該怎么辦呢?這是我們就想到使用?$$#為傳給shell腳本的參數(shù)個數(shù),但是上例中 echo “$$#”后顯示的其實是參數(shù)個數(shù),而使用eval echo “$$#”才顯示最后一個參數(shù)的內(nèi)容。?
對上述第3點補充:??? ????今天學習eval命令時,發(fā)現(xiàn)了這個問題:??? ????echo?"Last?argument?is?$(eval?echo?$$#)"?a?b?c?d?e??? ????這句話本意打印:Last?argument?is?e??? ????但實際打印的是:Last?argument?is?-bash?a?b?c?d?e??? ??? ????$#一般用在腳本中的,用在命令行的話就要先使用set設置位置參數(shù),因此修改為如下:??? ????set?-?a?b?c?d?e??? ????echo?"Last?argument?is?$(eval?echo?$$#)"??? ????Last?argument?is?e??? ??? ????set?-?a?b?c?d?e?f??? ????echo?"Last?argument?is?$(eval?echo?$#)"??? ????Last?argument?is?6
4、條件篩選?
在file文件中寫入兩列數(shù)據(jù),第一列對應KEY 、第二列為VALUE,使用eval命令將KEY與VALUE的值對應起來,從文件中讀取?
eval進階:
?? ?1.shell 也提供了 eval 命令,如同熟悉的其他腳本語言,會將它的參數(shù)做為命令執(zhí)行,初看會疑惑為什么shell要提供兩種動態(tài)執(zhí)行命令字串的機制,但是經(jīng)過仔細分析,才發(fā)現(xiàn)shell的eval同其他語言有很大區(qū)別。
?? ?2.shell 中的 eval
?? ??? ?2.1 不能獲得函數(shù)處理結(jié)果 ,如1所說,所有命令,函數(shù)的處理結(jié)果只能通過 “來獲得,那么其它語言中利用eval來獲得動態(tài)生成代碼執(zhí)行后的輸出變得不可能。
?? ??? ?2.2 eval 嵌套無意義 ,在其他語言中可以通過 eval(eval(“code”)),來執(zhí)行(執(zhí)行動態(tài)生成的code的返回),而由于shell 中 eval 將后面的eval命令簡單當作命令字符串執(zhí)行,失去了嵌套作用,嵌套被命令替換取代。
eval的作用是再次執(zhí)行命令行處理,也就是說,對一個命令行,執(zhí)行兩次命令行處理。這個命令要用好,就要費一定的功夫。我舉兩個例子,拋磚引玉.
例子1:用eval技巧實現(xiàn)shell的控制結(jié)構(gòu)for
[root@home?root]#?cat?myscript1???? QUOTE:???? #!/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里有兩個很特殊的變量,它們保存了參數(shù)列表。???? ???? $*,保存了以$IFS指定的分割符所分割的字符串組。???? $@,原樣保存了參數(shù)列表,也就是"$1""$2"...
這里我使用了函數(shù)遞歸以及eval實現(xiàn)了for結(jié)構(gòu)。
當執(zhí)行eval $@時,它經(jīng)歷了步驟如下:
第1步,分割成eval $@
第6步,擴展$@為hostname
第11步,找到內(nèi)置命令eval
重復一次命令行處理,第11步,找到hostname命令,執(zhí)行。
注意:也許有人想當然地認為,何必用eval呢?直接$@來執(zhí)行命令就可以了嘛。
例子2:一個典型錯誤的例子
如果命令行復雜的話(包括管道或者其他字符),直接執(zhí)行$a字符串的內(nèi)容就會出錯。分析如下。
$a的處理位于參數(shù)擴展,也就是說,跳過了管道分析,于是”|”, “cut”, “-f1”, “-d”都變成了id命令的參數(shù),當然就出錯啦。
但使用了eval,它把第一遍命令行處理所得的”id”, “|”, “cut”, “-f1”, “-d”這些字符串再次進行命令行處理,這次就能正確分析其中的管道了。
總而言之:要保證你的命令或腳本設計能正確通過命令行處理,跳過任意一步,都可能造成意料外的錯誤!
相關(guān)推薦: