鍍金池/ 教程/ Linux/ shell 學(xué)習(xí)三十八天---執(zhí)行順序和 eval
shell 學(xué)習(xí)四十五天---xargs
shell學(xué)習(xí)第三天
shell 學(xué)習(xí)十五天---join 連接字段
shell 學(xué)習(xí)第二天
shell 學(xué)習(xí)四十三天---臨時性文件的建立與使用
shell 學(xué)習(xí)第六天---小結(jié)
shell 學(xué)習(xí)三十三天---關(guān)于重定向
shell 學(xué)習(xí)二十九天---循環(huán)
shell 學(xué)習(xí)二十四天---提取開頭或結(jié)尾數(shù)行
shell 學(xué)習(xí)第十天---sed 查找與替換
shell 學(xué)習(xí)第十一天---sed 正則的精確控制
shell 學(xué)習(xí)三十天---break,continue,shift,getopts
shell 學(xué)習(xí)---小結(jié)
shell 學(xué)習(xí)三十一天---函數(shù)問題
shell 學(xué)習(xí)第四天---華麗的 printf 輸出
shell 學(xué)習(xí)三十五天---波浪號展開與通配符
shell 學(xué)習(xí)十九天---文本塊排序
shell 學(xué)習(xí)十二天---行與字符串
shell 學(xué)習(xí)二十一天---重新格式化段落
shell 學(xué)習(xí)十八天---文本排序
shell 學(xué)習(xí)十三天---sed 案例分析
shell 學(xué)習(xí)四十一天---列出文件 ls 和 od 命令
shell 學(xué)習(xí)十七天---awk 命令
shell 學(xué)習(xí)三十六天---命令替換
shell 學(xué)習(xí)十六天---join 練習(xí)
shell 學(xué)習(xí)三十二天---read 讀取一行
shell 學(xué)習(xí)二十二天---計算行數(shù),字?jǐn)?shù)以及字符數(shù)
shell 學(xué)習(xí)小總結(jié)---本章小結(jié)
shell 學(xué)習(xí)第八天---擴(kuò)展正則表達(dá)式(ERE)
shell 學(xué)習(xí)四十二天---使用 touch 更新文件時間
shell 學(xué)習(xí)二十八天---case 語句
shell 學(xué)習(xí)三十九天---內(nèi)建命令
shell 學(xué)習(xí)第一天
shell 學(xué)習(xí)三十四天---printf 詳解
shell 學(xué)習(xí)二十六天---變量與算數(shù)
shell 學(xué)習(xí)三十八天---執(zhí)行順序和 eval
shell 學(xué)習(xí)四十四天---尋找文件
shell 學(xué)習(xí)二十五天---神器的管道符
shell 學(xué)習(xí)十四天---使用 cut 選定字段
shell 學(xué)習(xí)第五天---基本的I/O重定向
shell 學(xué)習(xí)四十天---awk 的驚人表現(xiàn)
shell 學(xué)習(xí)二十天---sort 的其他內(nèi)容以及 uniq 命令
shell 學(xué)習(xí)二十三天---打印
shell 學(xué)習(xí)第九天---分組
shell 學(xué)習(xí)四十八天---文件校驗和匹配
shell 學(xué)習(xí)二十七天---退出狀態(tài)和 if 語句
shell 學(xué)習(xí)四十七天---文件比較 cmp,diff,patch
shell 學(xué)習(xí)第七天---基礎(chǔ)正則表達(dá)式(BRE)
shell 學(xué)習(xí)四十六天---文件系統(tǒng)的空間信息 df 和 du 命令
shell 學(xué)習(xí)三十七天---引用
shell 學(xué)習(xí)小結(jié)

shell 學(xué)習(xí)三十八天---執(zhí)行順序和 eval

shell 從標(biāo)準(zhǔn)輸入或腳本中讀取的每一行稱為管道,它包含了一個或多個命令,這些命令被一個或多個管道字符(|)隔開.

事實上嗨喲很多特殊符號可用來分割單個的命令:分號(;),管道(|),&,邏輯 AND(&&),邏輯 OR(||).對于每一個地區(qū)的管道,shell 都會將命令分割,為管道設(shè)置 I/O,并且對每一個命令依次執(zhí)行下面的操作.

看起來很復(fù)雜,但是每一個步驟都是在 shell 的內(nèi)存里發(fā)生的,shell 不會真的把每個步驟的發(fā)生演示給我們看.所以這是我們分析 shell 內(nèi)存的情況,從而知道每個階段的命令行是如何被轉(zhuǎn)換的.
案例:

mkdir /tmp/x #建立臨時性目錄  
cd /tmp/x #切換到該目錄  
touch f1 f2 #建立文件  
f=f y=”a b” #賦值兩個變量  
echo ~+/${f}[12] $y $(echo cmd subst) $((3+2))>out      #忙碌的命令  

上述命令的執(zhí)行步驟:

  1. 命令一開始會根據(jù) shell 語法而分割為 token.最重要的一點是:I/O 重定向>out 在這里是被識別的,并存儲供稍后使用.流程繼續(xù)處理下面這行,其中每個 token 的范圍顯示于命令下方的行上:
    echo ~+/${f}[12] $y $(echo cmd subst) $((3 + 2))
    | 1 | |----- 2 ----| |3 | |-------- 4----------| |----5-----|
  2. 堅持第一個單詞(echo)是否為關(guān)鍵字,例如 if 或 for.在這里不是,所以命令行不變繼續(xù)執(zhí)行.
  3. 堅持第一個單詞(依然是 echo)是否為別名.這里不是,所以命令行不變繼續(xù)處理.
  4. 掃描所有單詞是否需要波浪號展開.在這里~+等同于$PWD,也就是當(dāng)前目錄.token2 將被修改,處理繼續(xù)如下:
    echo /tmp/x/${f}[12] $y $(echo cmd subst) $((3 + 2))
    | 1 | |------- 2 -------| |3 | |-------- 4----------| |----5-----|
  5. 變量展開:token2 與 3 都被修改.產(chǎn)生:
    echo /tmp/x/${f}[12] a b $(echo cmd subst) $((3 + 2))
    | 1 | |------- 2 -------| | 3 | |-------- 4----------| |----5-----|
  6. 處理命令替換.注意,這里可遞歸引用列表里的所有步驟!在此例中,因為我們要試圖讓所有的東西容易理解,因此命令修改了token4,結(jié)果:
    echo /tmp/x/${f}[12] a b cmd subst $((3 + 2))
    | 1 | |------- 2 -------| | 3 | |--- 4 ----| |----5-----|
  7. 執(zhí)行算術(shù)替換 .修改 token5,結(jié)果:
    echo /tmp/x/${f}[12] a b cmd subst 5
    | 1 | |------- 2 -------| | 3 | |--- 4 ----| |5|
  8. 前面所有的展開產(chǎn)生的結(jié)果,都將再一次被掃描,看看是否有$IFS 字符.如果有,則他們是作為分隔符,產(chǎn)生額外的單詞.例如,兩個字符$y 原來是組成一個單詞,但展開式”a 空格 b”,在此階段被切分為兩個單詞:a 與 b.相同方式也應(yīng)用于命令替換$(echo cmd subst)的結(jié)果上.先前的 token3 變成了 token3 與 4.先前的 token4 則成了 token5 與 6.結(jié)果:
    echo /tmp/x/${f}[12] a b cmd subst 5
    | 1 | |------- 2 -------| 3 4 |-5-| |- 6 -| 7
  9. 通配符展開.token2 變成了 token2 與 token3:
    echo /tmp/x/$f1 /tmp/x/$f2 a b cmd subst 5
    | 1 | |---- 2 ----| |---- 3 ----| 4 5 |-6-| |- 7 -| 8
  10. 這時,shell 已經(jīng)準(zhǔn)備好了要執(zhí)行最后的命令了,他會去尋找 echo.正好 ksh93 與 bash 的 echo 都內(nèi)建到 shell 中了
    11.shell 實際執(zhí)行命令.首先執(zhí)行>out 的 I/O 重定向,在調(diào)用內(nèi)部的 echo 版本,顯示最后的參數(shù).

最后的結(jié)果:

$cat out  
/tmp/x/f1 /tmp/x/f2 a b cmd subst 5  

eval 語句
shell 中的 eval 這個命令很神奇,他能把字符串當(dāng)做命令來執(zhí)行.PS:這個字符串必須是可執(zhí)行的 bash 命令才可以.
案例:
eval “l(fā)s” #輸出當(dāng)前目錄的所有文件

語法: eval [參數(shù)]
補(bǔ)充說明:eval 可讀取一連串的參數(shù),然后再依慘呼本身的特性來執(zhí)行.
參數(shù):不限數(shù)目,彼此之間用分號隔開.
案例:我有一個文件test.txt
命令:cat test.txt
輸出:hello world
命令:myfile="cat test.txt"
命令:echo $myfile
輸出:cat test.txt
命令:eval $myfile
輸出:hello world
eval $myfile這條命令可以看出,eval 進(jìn)行了變量替換,將字符串中屬于 bash 的命令執(zhí)行了.
把拼接起來的字符串當(dāng)作命令執(zhí)行,這就是 eval 的神奇之處.

subShell 與代碼塊
subShell 是一群被括在圓括號里的命令,這些命令會在另外的進(jìn)程中執(zhí)行.當(dāng)你需要讓一小組的命令在不同的目錄下執(zhí)行時,這種方式可以讓你不必修改主腳本的目錄,直接處理這種情況.
例如:tar -cf -.| (cd /tmp;tar -xpf -)
左邊的 tar 命令會產(chǎn)生當(dāng)前目錄的 tar 打包文件,將他傳送給標(biāo)準(zhǔn)輸出.這份打包文件會通過管道傳遞給走遍的 subShell 里的命令.開頭的 cd 命令會先切換到新目錄,也就是讓大寶文件在此目錄下解開.然后,走遍的 tar 將從打包文件中解開文件.注意,執(zhí)行此管道的 shell(或腳本)并未更改他的目錄.

代碼塊概念上與 subShell 雷同,只不過他不會建立新的進(jìn)程.代碼塊里的命令以花括號({})括起來,且對主腳本的狀態(tài)會造成影響(例如他的當(dāng)前目錄).一般來說,花括號被視為 shell 關(guān)鍵字,意即他們只有出現(xiàn)在命令的第一個符號時會被識別.實際上:這表示你必須將結(jié)束花括號放置在換行字符或分號之后.例如:

 cd /home/directory||{  
echo could not change to /home/directory!>&2  
echo you lose !>&2  
exit1  
}  

I O重定向也可以套用 subShell 與代碼塊里.在該情況下,所有的命令會從重定向來源讀取它們的輸入或傳送他們的輸出.

??????????????????subShell與代碼塊

結(jié)構(gòu)

定界符

認(rèn)可的位置

另外的進(jìn)程

SubShell

()

行上的任何位置

代碼塊

{}

在換行字符,分號或關(guān)鍵字之后

注意:代碼塊里的 exit 會終止整個腳本.
我們通常在 shell 中運行一個腳本只需要簡單的調(diào)用./[script_name]即可,這種方式下,shell 會啟動一個子進(jìn)程來運行該腳本,稱為 subShell,當(dāng) subShell 運行完成,子進(jìn)程結(jié)束.父進(jìn)程的環(huán)境不會有任何改變.
案例:bash 代碼

 #!/bin/bash  
cd /var/cache  
testname="fine"  

分別在 shell 中運行

  1. ./test.sh;echo $testname 會發(fā)現(xiàn)還是位于原來的目錄中,$testname 的值書粗話為 null.
  2. source ./test.sh;echo $testname 這里就不一樣了,現(xiàn)在你位于/var/cache 中,$testname 的值也變成了 fine

用 source 命令來運行腳本,不會產(chǎn)生子進(jìn)程,腳本在 shell 的進(jìn)程空間中執(zhí)行,所以運行重定義的變量,執(zhí)行的操作,都會在 shell 的運行環(huán)境中保留下來.