Shell Script

linlinlinle發表於2018-11-15

目錄

建立指令碼

顯示訊息

變數

建立變數

只讀變數

刪除變數

命令替換

重定向輸入和輸出

輸出重定向

輸入重定向

管道

數學運算

方括號

浮點解決方案

退出指令碼


建立指令碼

在建立shell指令碼檔案時,必須在檔案的第一行指定要使用的shell。通常井號(#)用作註釋行,但第一行是個例外

#!/bin/bash
# This script displays the date and who's logged on
date
who

指令碼儲存在名為test1的檔案中,在直接執行指令碼時會出現下面問題:

$ test1
bash: test1: command not found

你要跨過的第一個障礙是讓bash shell能找到你的指令碼檔案,只需採取以下三種作法之一:

  • 將shell指令碼檔案所處的目錄新增到PATH環境變數中;
$ PATH=$PATH:.
$ test1
  • 作為直譯器引數:直接執行直譯器,其引數就是 shell 指令碼的檔名
/bin/bash test.sh

這種方式執行的指令碼,不需要在第一行指定直譯器資訊,寫了也沒用。

  • 在提示符中用絕對或相對檔案路徑來引用shell指令碼檔案(需要修改許可權)

我們採用第二種方式將指令碼檔案的確切位置告訴shell。為了引用當前目錄下的檔案,可以在shell中使用單點操作符。

$ ./test1
bash: ./test1: Permission denied
$

現在shell找到了指令碼檔案,但還有一個問題。shell指明瞭你還沒有執行檔案的許可權。下一步是通過chmod命令賦予檔案屬主執行檔案的許可權

$ chmod u+x test1
$ ./test1
Mon Feb 21 15:38:19 EST 2014
Christine tty2 2014-02-21 15:26
Samantha tty3 2014-02-21 15:26
Timothy tty1 2014-02-21 15:26
user tty7 2014-02-19 14:03 (:0)
user pts/0 2014-02-21 15:21 (:0.0) $

顯示訊息

echo命令後面加上了一個字串,該命令就能顯示出這個文字字串。echo命令可用單引號或雙引號來劃定文字字串

$ echo This is a test
This is a test
$ echo Let's see if this'll work
Lets see if thisll work
$ echo "This is a test to see if you're paying attention"
This is a test to see if you're paying attention
$ echo 'Rich says "scripting is easy".'
Rich says "scripting is easy".

在指令碼執行中,但如果想把文字字串和命令輸出顯示在同一行中,可以用echo語句的-n引數。

#!/bin/bash
echo -n "The time and date are: "

date

$ ./test1
The time and date are: Mon Feb 21 15:42:23 EST 2014

變數

  • 建立變數

除了環境變數,shell指令碼還允許在指令碼中定義和使用自己的變數。使用等號將值賦給使用者變數。在變數、等號和值之間不能出現空格。shell指令碼會自動決定變數值的資料型別

var1=10
var2=-57
var3=testing
var4="still more testing"

使用一個定義過的變數,只要在變數名前面加美元符號即可

  • 只讀變數

readonly 命令可以將變數定義為只讀變數,只讀變數的值不能被改變,也不能被刪

$ readonly var1=10
$ var=11
-bash: var: 只讀變數
  • 刪除變數

$ unset var
-bash: unset: var: 無法反設定: 只讀 variable
$ unset var1
$ echo $var1
$
  • 命令替換

  從命令輸出中提取資訊,並將其賦給變數,$()格式命令輸出賦給變數。shell會執行命令替換符號中的命令,並將其輸出賦給變數testing

$ testing=$(date)

下面例子中,在指令碼中通過命令替換獲得當前日期並用它來生成唯一檔名 。today變數是被賦予格式化後的date命令的輸出。+%y%m%d格式告訴date命令將日期顯示為兩位數的年月日的組合。

#!/bin/bash
# copy the /usr/bin directory listing to a log file
today=$(date +%y%m%d)
ls /usr/bin -al > log.$today

  

$ date +%y%m%d
140131
$

重定向輸入和輸出

  • 輸出重定向

最基本的重定向將命令的輸出傳送到一個檔案中。bash shell用大於號(>)來完成這項功能:

command > outputfile

之前顯示器上出現的命令輸出會被儲存到指定的輸出檔案中。如果輸出檔案已經存在了,重定向操作符會用新的檔案資料覆蓋已有檔案。

$ 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
$

雙大於號(>>)命令將輸出追加到已有檔案中

  • 輸入重定向

 輸入重定向符號是小於號(<):
 

command < inputfile

wc命令可以對對資料中的文字進行計數。預設情況下,它會輸出3個值: 文字的行數; 文字的詞數; 文字的位元組數。
通過將文字檔案重定向到wc命令,你立刻就可以得到檔案中的行、詞和位元組的計數

$ wc < test6
2 11 60
$

還有另外一種輸入重定向的方法,稱為內聯輸入重定向。這種方法無需使用檔案進行重定向,只需要在命令列中指定用於輸入重定向的資料就可以了。 

內聯輸入重定向符號是遠小於號(<<)。除了這個符號,你必須指定一個文字標記來劃分輸入資料的開始和結尾。任何字串都可作為文字標記,但在資料的開始和結尾文字標記必須一致。

command << marker    #marker為文字標記符
data                #data為輸入給command的資料
marker

在命令列上使用內聯輸入重定向時,shell會用PS2環境變數中定義的次提示符來提示輸入資料。

$ wc << EOF
> test string 1
> test string 2
> test string 3
> EOF
3 9 42
$

 

管道

有時需要將一個命令的輸出作為另一個命令的輸入。這可以用重定向來實現,只是有些笨拙。通過標準輸出重定向,rpm命令的輸出被重定向到了檔案 rpm.list。命令完成後,rpm.list儲存著系統中所有已安裝的軟體包列表。接下來,輸入重定向將rpm.list檔案的內容傳送給sort命令,該命令按字母順序對軟體包名稱進行排序。

$ rpm -qa > rpm.list
$ sort < rpm.list
abrt-1.1.14-1.fc14.i686
abrt-addon-ccpp-1.1.14-1.fc14.i686
abrt-addon-kerneloops-1.1.14-1.fc14.i686
abrt-addon-python-1.1.14-1.fc14.i686
acl-2.2.49-8.fc14.i686
[...]

我們用不著將命令輸出重定向到檔案中,可以將其直接重定向到另一個命令。這個過程叫作管道連線。在第一個命令產生輸出的同時,輸出會被立即送給第二個命令。資料傳輸不會用到任何中間檔案或緩衝區。

command1 | command2
$ rpm -qa | sort
abrt-1.1.14-1.fc14.i686
abrt-addon-ccpp-1.1.14-1.fc14.i686
abrt-addon-kerneloops-1.1.14-1.fc14.i686
abrt-addon-python-1.1.14-1.fc14.i686
acl-2.2.49-8.fc14.i686
[...]

可以在一條命令中使用任意多條管道 

$ rpm -qa | sort | more

可以搭配使用重定向和管道來將輸出儲存到檔案中

$ rpm -qa | sort > rpm.list

數學運算

  • 方括號

 在bash中,在將一個數學運算結果賦給某個變數時,可以用美元符和方括號($[ operation ])將數學表示式圍起來。bash shell數學運算子只支援整數運算

$ var1=$[1 + 5]
$ echo $var1
6
$ var2=$[$var1 * 2]
$ echo $var2
12
$
  • 浮點解決方案

 內建的bash計算器,叫作bc。要退出bash計算器,你必須輸入quit

$ bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'. 
12*0.5
6.0
quit
$

浮點運算是由內建變數scale控制的。scale變數的預設值是0。在scale值被設定前,bash計算器的計算結果不包含小數位。在將其值設定成4後,bash計算器顯示的結果包含四位小數。-q命令列選項可以不顯示bash計算器冗長的歡迎資訊。

$ bc -q
3.44 / 5
0
scale=4
3.44 / 5
.6880
quit
$

除了普通數字,bash計算器還能支援變數。

$ bc -q
var1=10
var1 * 4
40
quit
$

在指令碼中使用bc

variable=$(echo "options; expression" | bc)

第一部分options允許你設定變數。如果你需要不止一個變數,可以用分號將其分開。expression引數定義了通過bc執行的數學表示式。

$ cat test9
#!/bin/bash
var1=$(echo "scale=4; 3.44 / 5" | bc)
echo The answer is $var1
$ chmod u+x test9
$ ./test9
The answer is .6880

退出指令碼

shell中執行的每個命令都使用退出狀態碼(exit status)告訴shell它已經執行完畢。退出狀態碼是一個0~255的整數值,在命令結束執行時由命令傳給shell。可以捕獲這個值並在指令碼中使用。Linux提供了一個專門的變數$?來儲存上個已執行命令的退出狀態碼。

Linux退出狀態碼
0 命令成功結束 $ date
Sat Jan 15 10:01:30 EDT 2014
$ echo $?
0
1 一般性未知錯誤(是給某個命令提供了無效引數) $ date %t
date: invalid date '%t'
$ echo $?
1
$
2 不適合的shell命令  
126 命令不可執行(沒有許可權) $ ./myprog.c
-bash: ./myprog.c: Permission denied
$ echo $?
126
$
127 沒找到命令 $ asdfg
-bash: asdfg: command not found
$ echo $?
127
128 無效的退出引數  
130 通過Ctrl+C終止的命令  
255 正常範圍之外的退出狀態碼  

預設情況下,shell指令碼會以指令碼中的最後一個命令的退出狀態碼退出。exit命令允許你在指令碼結束時指定一個退出狀態碼。可以在exit命令的引數中使用變數.

$ cat test13
#!/bin/bash
# testing the exit status
var1=10
var2=30
var3=$[$var1 + $var2]
echo The answer is $var3
exit 5
$ chmod u+x test13
$ ./test13
The answer is 40
$ echo $?
5
$

 

相關文章