管道:管道符;cat和more命令
重定向:文件標識符:I/O重定向符號及其用法;exec命令;代碼塊重定向
命令行處理:命令行處理流程;eval命令
管道:
管道是Linux編程中最常用的技術之一,Shell編程中豎杠符號:“|”
command1 | command2 | command3 | … |commandn
command1到commandn表示Linux的n個命令,這n個命令利用管道進行通信
cat和more命令都用來顯示文件內容,
cat:顯示文件時不提供分頁功能,more:顯示超過一頁的文件時提供了分頁功能
cat命令還可以同時顯示多個文件:
cat file1 file2 file3 … filen
重定向:
I/O重定向是一個過程,這個過程捕捉一個文件、或命令、或程序、或腳本、甚至代碼塊(code block)的輸出,然后把捕捉到的輸出,作為輸入發送給另外一個文件、或命令、或程序、或腳本
文件標識符是從0開始到9結束的整數,指明了與進程相關的特定數據流的源
Linux系統啟動一個進程(該進程可能用于執行Shell命令)時,將自動為該進程打開三個文件:標準輸入、標準輸出和標準錯誤輸出,分別由文件標識符0、1、2標識
下圖描述了stdin、stout、stderr和Shell命令的關系,Shell命令從標準輸入讀取輸入數據,將輸出送到標準輸出,如果該命令在執行過程中發生錯誤,則將錯誤信息輸出到標準錯誤輸出
默認情況下,標準輸入與鍵盤輸入相關聯,標準輸出和標準錯誤輸出與顯示器相關聯
符號 意義
cmd1 | cmd2 管道符,將cmd1的標準輸出作為cmd2的標準輸入
> filename 將標準輸出寫到文件filename之中
< filename 將文件filename的內容讀入到標準輸入之中
>> filename 將標準輸出寫到文件filename之中,若filename文件已存在,則將標準輸出追加到filename已有內容之后
>| filename 即使noclobber選項已開啟,仍然強制將標準輸出寫到文件filename之中,即將filename文件覆蓋掉
n>| filename 即使noclobber選項已開啟,仍然強制將FD為n的輸出寫到文件filename之中,即將filename文件覆蓋掉
n> filename 將FD為n的輸出寫到文件filename之中
n< filename 將文件filename的內容讀入到FD n之中
n>> filename 將FD為n的輸出寫到文件filename之中,若filename文件已存在,則將FD為n的輸出追加到filename已有內容之后
<<delimiter 此處文檔(Here-document)
注意:cat和>符號結合成為簡易文本編輯器
cat后不加任何參數時,cat命令的輸入:標準輸入,即鍵盤輸入
利用I/O重定向符號“>”將鍵盤輸入寫入文件
cat > newfile:可輸入需要寫到newfile的內容,最后按CTRL+D結束對newfile的編輯
>>:用于在已有文件后追加一些文本
>|符:強制覆蓋文件的符號,它與Shell的noclobber選項有關系,如果noclobber選項開啟,表示不允許覆蓋任何文件,而>|符號則可以不管noclobber選項的作用,強制將文件覆蓋
重定向標準錯誤輸出,需要使用文件標識符2
2> newfile
<是I/O重定向的輸入符號,它可將文件內容寫到標準輸入之中
例10-20
<<delimiter符號稱為此處文檔(Here-document),delimiter稱為分界符,該符號表明:Shell將分界符delimiter之后直至下一個delimiter之前的所有內容作為輸入
exec命令可以通過文件標識符打開或關閉文件,也可將文件重定向到標準輸入,及將標準輸出重定向到文件
execin.sh腳本使用exec將stdin重定向到文件:
#!/bin/bash
exec 8<&0 //將標準輸入重定向到文件8中
exec < hfile //將hfile的內容讀入標準輸入中 分別為a ,b變量
read a
read b
echo "—————————"
echo $a
echo $b
echo "Close FD 8:"
exec 0<&8 8<&- //將文件8的內容拷貝到標準輸入 然后將8文件關閉
echo -n "Pls. Enter Data:"
read c //標準輸入中讀入c
echo $c
execout.sh腳本將stdout重定向到文件
#!/bin/bash
exec 8>&1 //將文件8的內容拷貝到標準輸出
exec > loggg //將標準輸出的內容拷貝到loggg文件
echo "Output of date command"
date //時間
echo "Output of df command"
df
exec 1>&8 8>&- //將標準輸出的內容拷貝到文件8 ,關閉文件8
echo "——————————–"
echo "Output of date command"
date
echo "Output of df command"
df
符號 意義
n>&m 將FD為m的輸出拷貝到FD為n的文件
n<&m 將FD為m的輸入拷貝到FD為n的文件
n>&- 關閉FD為n的輸出
n<&- 關閉FD為n的輸入
&>file 將標準輸出和標準錯誤輸出重定向到文件
代碼塊重定向:指在代碼塊內將標準輸入或標準輸出重定向到文件,而在代碼塊之外還是保留默認狀態
代碼塊重定向是指對標準輸入或標準輸出的重定向只在代碼塊內有效
可以重定向的代碼塊可以是while、until、for等循環結構,也可以是if/then測試結構,甚至可以是函數
代碼塊輸入重定向符號是<,輸出重定向符號是>
rewhile.sh腳本演示while循環的重定向:
#!/bin/bash
ls /etc > loggg //輸出重定向
while [ "$filename" != "rc.d" ]; do
read filename
let "count +=1"
done < loggg //從logg中讀取文件名
echo "$count times read"
echo -n "—–Pls. Input Data:—–"
read test
echo $test
refor.sh腳本演示for循環的重定向:
#refor.sh腳本:for循環的重定向
#!/bin/bash
#將ls /etc的結果寫到loggg文件中
ls /etc > loggg
#計算loggg文件的最大行數,并賦給maxline變量
#這是與while和until循環最大的區別
#靈活運用了輸入重定向符號<,類似用法可以參見圖10-25的例子
maxline=$(wc -l < loggg)
#搜索loggg文件中與rc.d所匹配的行,輸出匹配行的行數
for filename in `seq $maxline` #利用seq命令產生循環參數 $取值
do
read filename #按行讀取loggg中的數據
#let "count +=1"
#for循環中需要有if語句指定跳出循環的條件
if [ "$filename" = "rc.d" ]
then
break
else
let "count +=1"
fi
done < loggg #將標準輸入重定向到loggg文件
echo "$count times read"
#測試循環體外面的標準輸入是否被重定向
echo -n "—–Pls. Input Data:—–"
read test
echo $test
代碼塊重定向在一定程度上增強了Shell腳本處理文本文件的靈活性,它可以讓一段代碼很方便地處理一個文件(只要將該文件輸入重定向到該代碼塊)
命令行處理
命令行處理解釋了Shell如何處理一個命令的內部機制
Shell從標準輸入或腳本讀取的每一行稱為管道(pipeline),每一行包含一個或多個命令,這些命令用管道符隔開,Shell對每一個讀取的管道都按照下面的步驟處理:
1、將命令分割成令牌(token),令牌之間以元字符分隔,Shell的元字符集合是固定不變的,包括空格、Tab鍵、換行字符、分號(;)、小括號、輸入重定向符(<)、輸出重定向符(>)、管道符(|)和&符號,令牌可以是單詞(word)、關鍵字,也可以是I/O重定向器和分號。
2、檢查命令行的第一個令牌是否為不帶引號或反斜杠的關鍵字,如果此令牌是開放關鍵字,開放關鍵字指if、while、for或其他控制結構中的開始符號,Shell就認為此命令是復合命令,并為該復合命令進行內部設置,讀取下一條命令,再次啟動進程。如果此令牌不是復合命令的開始符號,如該令牌是then、else、do、fi、done等符號,這說明該令牌不應該處在命令行的首位,因此,Shell提示語法錯誤信息。
3、檢查命令行的第一個令牌是否為某命令的別名,這需要將此令牌與別名(alia)列表逐個比較,如果匹配,說明該令牌是別名,則將該令牌替換掉,返回步驟1,否則進入步驟4。這種機制允許別名遞歸,也允許定義關鍵字別名,比如可以用下面命令定義while關鍵字的別名when。
alias when=while
4、執行大括號展開,比如h{a,i}t展開為hat或hit。
5、將單詞開頭處的波浪號(~)替換成用戶的根目錄$HOME。
6、將任何開頭為$符號的表達式,執行變量替換。
7、將反引號內的表達式,執行命令替換。
8、將$((string))的表達式進行算術運算。
9、從變量、命令和算術替換的結果中取出命令行,再次進行單詞切分,與步驟1不同的是,此時不再用元字符分隔單詞,而是使用$IFS分隔單詞。
10、對于*、?、[…]等符號,執行通配符展開,生成文件名。
11、將第一個單詞作為命令,它可以是函數、內建命令和可執行文件。
12、在完成I/O重定向與其他類似事項后,執行命令。
eg: echo ~/i* $PWD `echo Yahoo Hadop` $((21*20)) > output
1、Shell首先將命令行分割成令牌,分割成的令牌如下,我們在命令行下方用數字標出各個令牌:
echo ~/i* $PWD `echo Yahoo Hadop` $((21*20))
|–1-||–2-| |–3—| |———4————-| |—–5—–|
需要注意的是,重定向>output雖已被識別,但是它不是令牌,Shell將在后面對I/O重定向進行處理。
2、檢查第一個單詞echo是否為關鍵字,顯然echo不是開放關鍵字,所以命令行繼續下面的判斷。
3、檢查第一個單詞echo是否為別名,echo不是別名,命令行繼續往下處理。
4、掃描命令行是否需要大括號展開,這條命令沒有大括號,命令行繼續往下處理。
5、掃描命令行是否需要波浪號展開,命令行中存在波浪號,令牌2將被修改,命令行變為如下形式:
echo /root/i* $PWD `echo Yahoo Hadop` $((21*20))
|–1-||—-2—| |–3—| |———4————-| |—–5—–|
6、掃描命令行中是否存在變量,若存在變量,則進行變量替換,該命令行中存在環境變量PWD,因此,令牌3將被修改,命令行變為如下形式:
echo /root/i* /root `echo Yahoo Hadop` $((21*20))
|–1-||—-2—| |–3-| |———4————-| |—–5—–|
7、掃描命令行中是否存在反引號,若存在則進行命令替換,該命令行存在命令替換,因此,令牌4將被修改,命令行變為如下形式:
echo /root/i* /root Yahoo Hadop $((21*20))
|–1-||—-2—| |–3-| |——-4——-| |—–5—–|
8、執行命令行中的算術替換,令牌5將被修改,命令行變為如下形式:
echo /root/i* /root Yahoo Hadop 420
|–1-||—-2—| |–3-| |——-4——-| |-5-|
9、Shell將對前面所有展開所產生的結果進行再次掃描,依據$IFS變量值對結果進行單詞分割,形成如下形式的新命令行:
echo /root/i* /root Yahoo Hadop 420
|–1-||—-2—| |–3-| |–4—| |—5–| |-6-|
由于$IFS是空格,因此,命令行被分割為6個令牌,Yahoo Hadop被分成兩個令牌。
10、掃描命令行中的通配符,并展開,該命令行中存在通配符*,展開后,命令行變為如下形式:
echo /root/indirect.sh /root/install.log /root/install.log.syslog /root Yahoo Hadop 420
|–1-||——–2———| |——–3——-| |———4—————-| |–5-| |—6–| |—7–| |-8-|
i*展開為當前目錄下所有以i開頭的文件,該目錄下有三個i開頭的文件:indirect.sh、install.log和install.log.syslog,因此,令牌2又被分為令牌2、3和4。
11、此時,Shell已經準備執行命令了,它尋找echo,echo是內建命令。
12、Shell執行echo命令,此時執行>output的I/O重定向,再調用echo命令,顯示最后參數。
命令行處理流程圖的左側跳轉箭頭從執行命令步驟跳轉到初始步驟,這正是eval命令的作用
eval命令將其參數作為命令行,讓Shell重新執行該命令行,eval的參數再次經過Shell命令行處理的12個步驟
eval在處理簡單命令時,與直接執行該命令無甚區別
演示了eval執行復雜命令:
#!/bin/bash
while read NAME VALUE
do
eval "${NAME}=${VALUE}"
#${NAME}=${VALUE}
done <evalsource
echo "var1=$var1"
echo "var2=$var2"
echo "var3=$var3"
echo "var4=$var4"
echo "var5=$var5"
其中 evalsource:
var1 APPLE
var2 BAIDU
var3 CAMEL
var4 DOT
var5 EMUL
var1 APPLE 最后的效果是:$var1=APPLE
evalre.sh腳本關鍵語句eval “${NAME}=${VALUE}”,第1輪結束后命令變為: var1=APPLE;再次將該命令提交到Shell,成功實現var1變量的賦值
evalre.sh腳本還使用了代碼塊重定向,實現對evalsource文件的遍歷
pipe變量賦為管道符, ls $pipe wc -l發生錯誤:第1步掃描沒有發現有管道符,直到第6步變量替換之后命令行才變成ls | wc -l,第9步根據$IFS變量將命令行重新分割成4個令牌,第11步將ls當作命令,后面的3個令牌|、wc和-l被解析為ls命令的參數,由于該目錄下沒有|和wc等文件或目錄,因此,Shell報語法錯誤
eval ls $pipe wc –l正確執行,第1輪的結果,ls | wc -l命令行被重新提交到Shell
原創文章,作者:NddTx99521,如若轉載,請注明出處:http://www.www58058.com/29016