本篇內容均摘自《Linux命令行與shell腳本編程大全》,個人認為需要重點學習的章節(jié)。【免費】Linux命令行與Shell腳本編程大全 第3版 PDF全本 21MB 百度網(wǎng)盤下載 - 今夕是何夕 - 博客園
重定向輸入和輸出
有些時候你想要保存某個命令的輸出而不僅僅只是讓它顯示在顯示器上。 bash shell提供了幾個操作符,可以將命令的輸出重定向到另一個位置(比如文件)。重定向可以用于輸入,也可以用于輸出,可以將文件重定向到命令輸入。本節(jié)介紹了如何在shell腳本中使用重定向。
11.5.1 輸出重定向
最基本的重定向將命令的輸出發(fā)送到一個文件中。 bash shell用大于號( >)來完成這項功能:command > outputfile
之前顯示器上出現(xiàn)的命令輸出會被保存到指定的輸出文件中。
$ 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)建了一個文件test6(通過默認的umask設置),并將date命令的輸出重定向到該文件中。如果輸出文件已經存在了,重定向操作符會用新的文件數(shù)據(jù)覆蓋已有文件。
$ who > test6
$ cat test6
user pts/0 Feb 10 17:55
現(xiàn)在test6文件的內容就是who命令的輸出。有時,你可能并不想覆蓋文件原有內容,而是想要將命令的輸出追加到已有文件中,比如你正在創(chuàng)建一個記錄系統(tǒng)上某個操作的日志文件。在這種情況下,可以用雙大于號( >>)來追加數(shù)據(jù)。
$ date >> test6
$ cat test6
user pts/0 Feb 10 17:55
Thu Feb 10 18:02:14 EDT 2014
test6文件仍然包含早些時候who命令的數(shù)據(jù),現(xiàn)在又加上了來自date命令的輸出。
輸入重定向
輸入重定向和輸出重定向正好相反。輸入重定向將文件的內容重定向到命令,而非將命令的輸出重定向到文件。輸入重定向符號是小于號( <):
command < inputfile
一個簡單的記憶方法就是:在命令行上,命令總是在左側,而重定向符號“指向”數(shù)據(jù)流動的方向。小于號說明數(shù)據(jù)正在從輸入文件流向命令。這里有個和wc命令一起使用輸入重定向的例子。
$ wc < test6
2 11 60
wc命令可以對對數(shù)據(jù)中的文本進行計數(shù)。默認情況下,它會輸出3個值:
1.文本的行數(shù)。2. 文本的詞數(shù)。3.文本的字節(jié)數(shù)。
通過將文本文件重定向到wc命令,你立刻就可以得到文件中的行、詞和字節(jié)的計數(shù)。這個例子說明test6文件有2行、 11個單詞以及60字節(jié)。還有另外一種輸入重定向的方法,稱為內聯(lián)輸入重定向( inline input redirection)。這種方法無需使用文件進行重定向,只需要在命令行中指定用于輸入重定向的數(shù)據(jù)就可以了。乍看一眼,這可能有點奇怪,但有些應用會用到這種方式(參見11.7節(jié))。內聯(lián)輸入重定向符號是遠小于號( <<)。除了這個符號,你必須指定一個文本標記來劃分輸入數(shù)據(jù)的開始和結尾。任何字符串都可作為文本標記,但在數(shù)據(jù)的開始和結尾文本標記必須一致。
command << marker
data
marker
在命令行上使用內聯(lián)輸入重定向時, shell會用PS2環(huán)境變量中定義的次提示符(參見第6章)來提示輸入數(shù)據(jù)。下面是它的使用情況。
$ wc << EOF
> test string 1
> test string 2
> test string 3
> EOF
3 9 42
次提示符會持續(xù)提示,以獲取更多的輸入數(shù)據(jù),直到你輸入了作為文本標記的那個字符串。wc命令會對內聯(lián)輸入重定向提供的數(shù)據(jù)進行行、詞和字節(jié)計數(shù)。
管道
和命令替換所用的反引號( `)一樣,管道符號在shell編程之外也很少用到。該符號由兩個豎線構成,一個在另一個上面。然而管道符號的印刷體通常看起來更像是單個豎線( |)。在美式鍵盤上,它通常和反斜線( \)位于同一個鍵。管道被放在命令之間,將一個命令的輸出重定向到另一個命令中:
command1 | command2
不要以為由管道串起的兩個命令會依次執(zhí)行。 Linux系統(tǒng)實際上會同時運行這兩個命令,在系統(tǒng)內部將它們連接起來。在第一個命令產生輸出的同時,輸出會被立即送給第二個命令。數(shù)據(jù)傳輸不會用到任何中間文件或緩沖區(qū)。例如:
$ rpm -qa | sort | more
這行命令序列會先執(zhí)行rpm命令,將它的輸出通過管道傳給sort命令,然后再將sort的輸出通過管道傳給more命令來顯示,在顯示完一屏信息后停下來。到目前為止,管道最流行的用法之一是將命令產生的大量輸出通過管道傳送給more命令。ls -l命令產生了目錄中所有文件的長列表。對包含大量文件的目錄來說,這個列表會相當長。通過將輸出管道連接到more命令,可以強制輸出在一屏數(shù)據(jù)顯示后停下來。
執(zhí)行數(shù)學運算
在shell腳本中有兩種途徑來進行數(shù)學運算。
expr 命令
最開始, Bourne shell提供了一個特別的命令用來處理數(shù)學表達式。 expr命令允許在命令行上處理數(shù)學表達式,但是特別笨拙。
$ expr 1 + 5
6
(個人備注:實際上我試的時候1和+,還有5之間沒有空格,輸出來是以下的結果:)
expr 1+5
1+5
盡管標準操作符在expr命令中工作得很好,但在腳本或命令行上使用它們時仍有問題出現(xiàn)。許多expr命令操作符在shell中另有含義(比如星號)。當它們出現(xiàn)在在expr命令中時,會得到一些詭異的結果。
$ expr 5 * 2
expr: syntax error
要解決這個問題,對于那些容易被shell錯誤解釋的字符,在它們傳入expr命令之前,需要使用shell的轉義字符(反斜線)將其標出來。
$ expr 5 \* 2
10
在shell腳本中使用expr命令也同樣復雜:
$ cat test6
#!/bin/bash
# An example of using the expr command
var1=10
var2=20
var3=$(expr $var2 / $var1)
echo The result is $var3
要將一個數(shù)學算式的結果賦給一個變量,需要使用命令替換來獲取expr命令的輸出:
$ chmod u+x test6
$ ./test6
The result is 2
使用方括號
bash shell為了保持跟Bourne shell的兼容而包含了expr命令,但它同樣也提供了一種更簡單的方法來執(zhí)行數(shù)學表達式。在bash中,在將一個數(shù)學運算結果賦給某個變量時,可以用美元符和方括號( $[ operation ])將數(shù)學表達式圍起來。
$ var1=$[1 + 5]
$ echo $var1
6
$ var2=$[$var1 * 2]
$ echo $var2
12
用方括號執(zhí)行shell數(shù)學運算比用expr命令方便很多。這種技術也適用于shell腳本。
$ cat test7
#!/bin/bash
var1=100
var2=50
var3=45
var4=$[$var1 * ($var2 - $var3)]
echo The final result is $var4
運行這個腳本會得到如下輸出。
$ chmod u+x test7
$ ./test7
The final result is 500
同樣,注意在使用方括號來計算公式時,不用擔心shell會誤解乘號或其他符號。 shell知道它不是通配符,因為它在方括號內。在bash shell腳本中進行算術運算會有一個主要的限制。請看下例:
$ cat test8
#!/bin/bash
var1=100
var2=45
var3=$[$var1 / $var2]
echo The final result is $var3
現(xiàn)在,運行一下,看看會發(fā)生什么:
$ chmod u+x test8
$ ./test8
The final result is 2
bash shell數(shù)學運算符只支持整數(shù)運算。若要進行任何實際的數(shù)學計算,這是一個巨大的限制。
浮點解決方案
有幾種解決方案能夠克服bash中數(shù)學運算的整數(shù)限制。最常見的方案是用內建的bash計算器,叫作bc。
- bc的基本用法
bash計算器實際上是一種編程語言,它允許在命令行中輸入浮點表達式,然后解釋并計算該表達式,最后返回結果。 bash計算器能夠識別:數(shù)字(整數(shù)和浮點數(shù)),變量(簡單變量和數(shù)組),注釋(以#或C語言中的/* */開始的行),表達式,編程語句(例如if-then語句),函數(shù)??梢栽趕hell提示符下通過bc命令訪問bash計算器。要退出bash計算器,你必須輸入quit。浮點運算是由內建變量scale控制的。必須將這個值設置為你希望在計算結果中保留的小數(shù)位數(shù),否則無法得到期望的結果。
$ bc -q
3.44 / 5
0
scale=4
3.44 / 5
.6880
quit
scale變量的默認值是0。在scale值被設置前, bash計算器的計算結果不包含小數(shù)位。在將其值設置成4后, bash計算器顯示的結果包含四位小數(shù)。 -q命令行選項可以不顯示bash計算器冗長的歡迎信息。除了普通數(shù)字, bash計算器還能支持變量。
$ bc -q
var1=10
var1 * 4
40
var2 = var1 / 5
print var2
2
quit
變量一旦被定義,你就可以在整個bash計算器會話中使用該變量了。 print語句允許你打印變量和數(shù)字。
- 在腳本中使用bc
現(xiàn)在你可能想問bash計算器是如何在shell腳本中幫助處理浮點運算的。還記得命令替換嗎?是的,可以用命令替換運行bc命令,并將輸出賦給一個變量?;靖袷饺缦拢簐ariable=$(echo "options; expression" | bc)。第一部分options允許你設置變量。如果你需要不止一個變量,可以用分號將其分開。expression參數(shù)定義了通過bc執(zhí)行的數(shù)學表達式。這里有個在腳本中這么做的例子。
$ cat test9
#!/bin/bash
var1=$(echo "scale=4; 3.44 / 5" | bc)
echo The answer is $var1
這個例子將scale變量設置成了四位小數(shù),并在expression部分指定了特定的運算。運行這個腳本會產生如下輸出。
$ 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
腳本定義了兩個變量,它們都可以用在expression部分,然后發(fā)送給bc命令。別忘了用美元符表示的是變量的值而不是變量自身。這個腳本的輸出如下。
$ ./test10
The answer for this is 2.2222
當然,一旦變量被賦值,那個變量也可以用于其他運算。
$ 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
這個方法適用于較短的運算,但有時你會涉及更多的數(shù)字。如果需要進行大量運算,在一個命令行中列出多個表達式就會有點麻煩。有一個方法可以解決這個問題。 bc命令能識別輸入重定向,允許你將一個文件重定向到bc命令來處理。但這同樣會叫人頭疼,因為你還得將表達式存放到文件中。最好的辦法是使用內聯(lián)輸入重定向,它允許你直接在命令行中重定向數(shù)據(jù)。在shell腳本中,你可以將輸出賦給一個變量。
variable=$(bc << EOF
options
statements
expressions
EOF
)
EOF文本字符串標識了內聯(lián)重定向數(shù)據(jù)的起止。記住,仍然需要命令替換符號將bc命令的輸賦給變量?,F(xiàn)在可以將所有bash計算器涉及的部分都放到同一個腳本文件的不同行。下面是在腳本中使用這種技術的例子。
$ 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
將選項和表達式放在腳本的不同行中可以讓處理過程變得更清晰,提高易讀性。 EOF字符串標識了重定向給bc命令的數(shù)據(jù)的起止。 當然, 必須用命令替換符號標識出用來給變量賦值的命令。你還會注意到,在這個例子中,你可以在bash計算器中賦值給變量。這一點很重要:在bash計算器中創(chuàng)建的變量只在bash計算器中有效,不能在shell腳本中使用。