本篇內(nèi)容均摘自《Linux命令行與shell腳本編程大全》慎陵,個(gè)人認(rèn)為需要重點(diǎn)學(xué)習(xí)的章節(jié)副渴。【免費(fèi)】Linux命令行與Shell腳本編程大全 第3版 PDF全本 21MB 百度網(wǎng)盤下載 - 今夕是何夕 - 博客園
重定向輸入和輸出
有些時(shí)候你想要保存某個(gè)命令的輸出而不僅僅只是讓它顯示在顯示器上空繁。 bash shell提供了幾個(gè)操作符府喳,可以將命令的輸出重定向到另一個(gè)位置(比如文件)窗声。重定向可以用于輸入,也可以用于輸出厌衙,可以將文件重定向到命令輸入距淫。本節(jié)介紹了如何在shell腳本中使用重定向。
11.5.1 輸出重定向
最基本的重定向?qū)⒚畹妮敵霭l(fā)送到一個(gè)文件中婶希。 bash shell用大于號(hào)( >)來(lái)完成這項(xiàng)功能:command > outputfile
之前顯示器上出現(xiàn)的命令輸出會(huì)被保存到指定的輸出文件中榕暇。
$ date > test6
$ ls -l test6
-rw-r--r-- 1 user user 29 Feb 10 17:56 test6
$ cat test6
Thu Feb 10 17:56:58 EDT 2014
重定向操作符創(chuàng)建了一個(gè)文件test6(通過(guò)默認(rèn)的umask設(shè)置),并將date命令的輸出重定向到該文件中喻杈。如果輸出文件已經(jīng)存在了彤枢,重定向操作符會(huì)用新的文件數(shù)據(jù)覆蓋已有文件。
$ who > test6
$ cat test6
user pts/0 Feb 10 17:55
現(xiàn)在test6文件的內(nèi)容就是who命令的輸出筒饰。有時(shí)堂污,你可能并不想覆蓋文件原有內(nèi)容,而是想要將命令的輸出追加到已有文件中龄砰,比如你正在創(chuàng)建一個(gè)記錄系統(tǒng)上某個(gè)操作的日志文件盟猖。在這種情況下,可以用雙大于號(hào)( >>)來(lái)追加數(shù)據(jù)换棚。
$ date >> test6
$ cat test6
user pts/0 Feb 10 17:55
Thu Feb 10 18:02:14 EDT 2014
test6文件仍然包含早些時(shí)候who命令的數(shù)據(jù)式镐,現(xiàn)在又加上了來(lái)自date命令的輸出。
輸入重定向
輸入重定向和輸出重定向正好相反固蚤。輸入重定向?qū)⑽募膬?nèi)容重定向到命令,而非將命令的輸出重定向到文件娘汞。輸入重定向符號(hào)是小于號(hào)( <):
command < inputfile
一個(gè)簡(jiǎn)單的記憶方法就是:在命令行上,命令總是在左側(cè)夕玩,而重定向符號(hào)“指向”數(shù)據(jù)流動(dòng)的方向你弦。小于號(hào)說(shuō)明數(shù)據(jù)正在從輸入文件流向命令。這里有個(gè)和wc命令一起使用輸入重定向的例子燎孟。
$ wc < test6
2 11 60
wc命令可以對(duì)對(duì)數(shù)據(jù)中的文本進(jìn)行計(jì)數(shù)禽作。默認(rèn)情況下,它會(huì)輸出3個(gè)值:
1.文本的行數(shù)揩页。2. 文本的詞數(shù)旷偿。3.文本的字節(jié)數(shù)。
通過(guò)將文本文件重定向到wc命令,你立刻就可以得到文件中的行萍程、詞和字節(jié)的計(jì)數(shù)幢妄。這個(gè)例子說(shuō)明test6文件有2行、 11個(gè)單詞以及60字節(jié)茫负。還有另外一種輸入重定向的方法蕉鸳,稱為內(nèi)聯(lián)輸入重定向( inline input redirection)。這種方法無(wú)需使用文件進(jìn)行重定向忍法,只需要在命令行中指定用于輸入重定向的數(shù)據(jù)就可以了置吓。乍看一眼,這可能有點(diǎn)奇怪缔赠,但有些應(yīng)用會(huì)用到這種方式(參見11.7節(jié))。內(nèi)聯(lián)輸入重定向符號(hào)是遠(yuǎn)小于號(hào)( <<)友题。除了這個(gè)符號(hào)嗤堰,你必須指定一個(gè)文本標(biāo)記來(lái)劃分輸入數(shù)據(jù)的開始和結(jié)尾。任何字符串都可作為文本標(biāo)記度宦,但在數(shù)據(jù)的開始和結(jié)尾文本標(biāo)記必須一致踢匣。
command << marker
data
marker
在命令行上使用內(nèi)聯(lián)輸入重定向時(shí), shell會(huì)用PS2環(huán)境變量中定義的次提示符(參見第6章)來(lái)提示輸入數(shù)據(jù)戈抄。下面是它的使用情況离唬。
$ wc << EOF
> test string 1
> test string 2
> test string 3
> EOF
3 9 42
次提示符會(huì)持續(xù)提示,以獲取更多的輸入數(shù)據(jù)划鸽,直到你輸入了作為文本標(biāo)記的那個(gè)字符串输莺。wc命令會(huì)對(duì)內(nèi)聯(lián)輸入重定向提供的數(shù)據(jù)進(jìn)行行、詞和字節(jié)計(jì)數(shù)裸诽。
管道
和命令替換所用的反引號(hào)( `)一樣嫂用,管道符號(hào)在shell編程之外也很少用到。該符號(hào)由兩個(gè)豎線構(gòu)成丈冬,一個(gè)在另一個(gè)上面嘱函。然而管道符號(hào)的印刷體通常看起來(lái)更像是單個(gè)豎線( |)埂蕊。在美式鍵盤上往弓,它通常和反斜線( \)位于同一個(gè)鍵。管道被放在命令之間蓄氧,將一個(gè)命令的輸出重定向到另一個(gè)命令中:
command1 | command2
不要以為由管道串起的兩個(gè)命令會(huì)依次執(zhí)行函似。 Linux系統(tǒng)實(shí)際上會(huì)同時(shí)運(yùn)行這兩個(gè)命令,在系統(tǒng)內(nèi)部將它們連接起來(lái)喉童。在第一個(gè)命令產(chǎn)生輸出的同時(shí)缴淋,輸出會(huì)被立即送給第二個(gè)命令。數(shù)據(jù)傳輸不會(huì)用到任何中間文件或緩沖區(qū)。例如:
$ rpm -qa | sort | more
這行命令序列會(huì)先執(zhí)行rpm命令重抖,將它的輸出通過(guò)管道傳給sort命令露氮,然后再將sort的輸出通過(guò)管道傳給more命令來(lái)顯示,在顯示完一屏信息后停下來(lái)钟沛。到目前為止畔规,管道最流行的用法之一是將命令產(chǎn)生的大量輸出通過(guò)管道傳送給more命令。ls -l命令產(chǎn)生了目錄中所有文件的長(zhǎng)列表恨统。對(duì)包含大量文件的目錄來(lái)說(shuō)叁扫,這個(gè)列表會(huì)相當(dāng)長(zhǎng)。通過(guò)將輸出管道連接到more命令畜埋,可以強(qiáng)制輸出在一屏數(shù)據(jù)顯示后停下來(lái)莫绣。
執(zhí)行數(shù)學(xué)運(yùn)算
在shell腳本中有兩種途徑來(lái)進(jìn)行數(shù)學(xué)運(yùn)算。
expr 命令
最開始悠鞍, Bourne shell提供了一個(gè)特別的命令用來(lái)處理數(shù)學(xué)表達(dá)式对室。 expr命令允許在命令行上處理數(shù)學(xué)表達(dá)式,但是特別笨拙咖祭。
$ expr 1 + 5
6
(個(gè)人備注:實(shí)際上我試的時(shí)候1和+掩宜,還有5之間沒(méi)有空格,輸出來(lái)是以下的結(jié)果:)
expr 1+5
1+5
盡管標(biāo)準(zhǔn)操作符在expr命令中工作得很好么翰,但在腳本或命令行上使用它們時(shí)仍有問(wèn)題出現(xiàn)牺汤。許多expr命令操作符在shell中另有含義(比如星號(hào))。當(dāng)它們出現(xiàn)在在expr命令中時(shí)浩嫌,會(huì)得到一些詭異的結(jié)果檐迟。
$ expr 5 * 2
expr: syntax error
要解決這個(gè)問(wèn)題码耐,對(duì)于那些容易被shell錯(cuò)誤解釋的字符锅减,在它們傳入expr命令之前伐坏,需要使用shell的轉(zhuǎn)義字符(反斜線)將其標(biāo)出來(lái)。
$ expr 5 \* 2
10
在shell腳本中使用expr命令也同樣復(fù)雜:
$ cat test6
#!/bin/bash
# An example of using the expr command
var1=10
var2=20
var3=$(expr $var2 / $var1)
echo The result is $var3
要將一個(gè)數(shù)學(xué)算式的結(jié)果賦給一個(gè)變量桦沉,需要使用命令替換來(lái)獲取expr命令的輸出:
$ chmod u+x test6
$ ./test6
The result is 2
使用方括號(hào)
bash shell為了保持跟Bourne shell的兼容而包含了expr命令每瞒,但它同樣也提供了一種更簡(jiǎn)單的方法來(lái)執(zhí)行數(shù)學(xué)表達(dá)式。在bash中纯露,在將一個(gè)數(shù)學(xué)運(yùn)算結(jié)果賦給某個(gè)變量時(shí),可以用美元符和方括號(hào)( $[ operation ])將數(shù)學(xué)表達(dá)式圍起來(lái)埠褪。
$ var1=$[1 + 5]
$ echo $var1
6
$ var2=$[$var1 * 2]
$ echo $var2
12
用方括號(hào)執(zhí)行shell數(shù)學(xué)運(yùn)算比用expr命令方便很多挤庇。這種技術(shù)也適用于shell腳本。
$ cat test7
#!/bin/bash
var1=100
var2=50
var3=45
var4=$[$var1 * ($var2 - $var3)]
echo The final result is $var4
運(yùn)行這個(gè)腳本會(huì)得到如下輸出贷掖。
$ chmod u+x test7
$ ./test7
The final result is 500
同樣嫡秕,注意在使用方括號(hào)來(lái)計(jì)算公式時(shí),不用擔(dān)心shell會(huì)誤解乘號(hào)或其他符號(hào)苹威。 shell知道它不是通配符,因?yàn)樗诜嚼ㄌ?hào)內(nèi)掷酗。在bash shell腳本中進(jìn)行算術(shù)運(yùn)算會(huì)有一個(gè)主要的限制。請(qǐng)看下例:
$ cat test8
#!/bin/bash
var1=100
var2=45
var3=$[$var1 / $var2]
echo The final result is $var3
現(xiàn)在泻轰,運(yùn)行一下,看看會(huì)發(fā)生什么:
$ chmod u+x test8
$ ./test8
The final result is 2
bash shell數(shù)學(xué)運(yùn)算符只支持整數(shù)運(yùn)算浮声。若要進(jìn)行任何實(shí)際的數(shù)學(xué)計(jì)算,這是一個(gè)巨大的限制。
浮點(diǎn)解決方案
有幾種解決方案能夠克服bash中數(shù)學(xué)運(yùn)算的整數(shù)限制雳锋。最常見的方案是用內(nèi)建的bash計(jì)算器,叫作bc玷过。
- bc的基本用法
bash計(jì)算器實(shí)際上是一種編程語(yǔ)言,它允許在命令行中輸入浮點(diǎn)表達(dá)式辛蚊,然后解釋并計(jì)算該表達(dá)式,最后返回結(jié)果袋马。 bash計(jì)算器能夠識(shí)別:數(shù)字(整數(shù)和浮點(diǎn)數(shù)),變量(簡(jiǎn)單變量和數(shù)組),注釋(以#或C語(yǔ)言中的/* */開始的行),表達(dá)式,編程語(yǔ)句(例如if-then語(yǔ)句),函數(shù)÷橇荩可以在shell提示符下通過(guò)bc命令訪問(wèn)bash計(jì)算器。要退出bash計(jì)算器桑谍,你必須輸入quit。浮點(diǎn)運(yùn)算是由內(nèi)建變量scale控制的锣披。必須將這個(gè)值設(shè)置為你希望在計(jì)算結(jié)果中保留的小數(shù)位數(shù)贿条,否則無(wú)法得到期望的結(jié)果增热。
$ bc -q
3.44 / 5
0
scale=4
3.44 / 5
.6880
quit
scale變量的默認(rèn)值是0。在scale值被設(shè)置前钓葫, bash計(jì)算器的計(jì)算結(jié)果不包含小數(shù)位。在將其值設(shè)置成4后础浮, bash計(jì)算器顯示的結(jié)果包含四位小數(shù)帆调。 -q命令行選項(xiàng)可以不顯示bash計(jì)算器冗長(zhǎng)的歡迎信息。除了普通數(shù)字豆同, bash計(jì)算器還能支持變量番刊。
$ bc -q
var1=10
var1 * 4
40
var2 = var1 / 5
print var2
2
quit
變量一旦被定義,你就可以在整個(gè)bash計(jì)算器會(huì)話中使用該變量了影锈。 print語(yǔ)句允許你打印變量和數(shù)字芹务。
- 在腳本中使用bc
現(xiàn)在你可能想問(wèn)bash計(jì)算器是如何在shell腳本中幫助處理浮點(diǎn)運(yùn)算的。還記得命令替換嗎鸭廷?是的枣抱,可以用命令替換運(yùn)行bc命令,并將輸出賦給一個(gè)變量辆床。基本格式如下:variable=$(echo "options; expression" | bc)轿秧。第一部分options允許你設(shè)置變量咨堤。如果你需要不止一個(gè)變量菇篡,可以用分號(hào)將其分開一喘。expression參數(shù)定義了通過(guò)bc執(zhí)行的數(shù)學(xué)表達(dá)式。這里有個(gè)在腳本中這么做的例子凸克。
$ cat test9
#!/bin/bash
var1=$(echo "scale=4; 3.44 / 5" | bc)
echo The answer is $var1
這個(gè)例子將scale變量設(shè)置成了四位小數(shù),并在expression部分指定了特定的運(yùn)算咪鲜。運(yùn)行這個(gè)腳本會(huì)產(chǎn)生如下輸出撞鹉。
$ chmod u+x test9
$ ./test9
The answer is .6880
也可以用shell腳本中定義好的變量疟丙。
$ cat test10
#!/bin/bash
var1=100
var2=45
var3=$(echo "scale=4; $var1 / $var2" | bc)
echo The answer for this is $var3
腳本定義了兩個(gè)變量,它們都可以用在expression部分览祖,然后發(fā)送給bc命令炊琉。別忘了用美元符表示的是變量的值而不是變量自身展蒂。這個(gè)腳本的輸出如下苔咪。
$ ./test10
The answer for this is 2.2222
當(dāng)然,一旦變量被賦值团赏,那個(gè)變量也可以用于其他運(yùn)算。
$ cat test11
#!/bin/bash
var1=20
var2=3.14159
var3=$(echo "scale=4; $var1 * $var1" | bc)
var4=$(echo "scale=4; $var3 * $var2" | bc)
echo The final result is $var4
這個(gè)方法適用于較短的運(yùn)算丝里,但有時(shí)你會(huì)涉及更多的數(shù)字体谒。如果需要進(jìn)行大量運(yùn)算杯聚,在一個(gè)命令行中列出多個(gè)表達(dá)式就會(huì)有點(diǎn)麻煩抒痒。有一個(gè)方法可以解決這個(gè)問(wèn)題。 bc命令能識(shí)別輸入重定向纷捞,允許你將一個(gè)文件重定向到bc命令來(lái)處理痢虹。但這同樣會(huì)叫人頭疼,因?yàn)槟氵€得將表達(dá)式存放到文件中惨缆。最好的辦法是使用內(nèi)聯(lián)輸入重定向,它允許你直接在命令行中重定向數(shù)據(jù)坯墨。在shell腳本中病往,你可以將輸出賦給一個(gè)變量捣染。
variable=$(bc << EOF
options
statements
expressions
EOF
)
EOF文本字符串標(biāo)識(shí)了內(nèi)聯(lián)重定向數(shù)據(jù)的起止停巷。記住榕栏,仍然需要命令替換符號(hào)將bc命令的輸賦給變量±俑鳎現(xiàn)在可以將所有bash計(jì)算器涉及的部分都放到同一個(gè)腳本文件的不同行。下面是在腳本中使用這種技術(shù)的例子式曲。
$ cat test12
#!/bin/bash
var1=10.46
var2=43.67
var3=33.2
var4=71
var5=$(bc << EOF
scale = 4
a1 = ( $var1 * $var2)
b1 = ($var3 * $var4)
a1 + b1
EOF
)
echo The final answer for this mess is $var5
將選項(xiàng)和表達(dá)式放在腳本的不同行中可以讓處理過(guò)程變得更清晰兰伤,提高易讀性医清。 EOF字符串標(biāo)識(shí)了重定向給bc命令的數(shù)據(jù)的起止会烙。 當(dāng)然柏腻, 必須用命令替換符號(hào)標(biāo)識(shí)出用來(lái)給變量賦值的命令五嫂。你還會(huì)注意到肯尺,在這個(gè)例子中则吟,你可以在bash計(jì)算器中賦值給變量氓仲。這一點(diǎn)很重要:在bash計(jì)算器中創(chuàng)建的變量只在bash計(jì)算器中有效敬扛,不能在shell腳本中使用啥箭。