Bash shell 腳本編程全攻略(上篇)

Bash shell 腳本編程全攻略(上篇)

 

什么是shell腳本呢?

當命令不在命令行上執行,而是通過一個文件執行時,該文件就稱為shell腳本,腳本以非交互的方式運行。Shell腳本把命令通過一些語法組織起來,便能實現特定的功能。

 

Shell腳本主要運用在系統運維中,主要功能有:

自動化常用命令;

執行系統管理和故障排除;

創建簡單的應用程序;

處理文本或文件。

 

Shell腳本創建與執行

Shell腳本通常在編輯器中編寫,由命令及其注釋組成,注釋是跟在井號(#)后面的內容,用來對腳本進行注釋。

腳本左上角的第一行會指出由哪個程序來執行腳本中的行。這一行通常稱為shbang行,必須為頂端第一行,如由bash來執行則為:

#!/bin/bash

在執行shell腳本時,須先給予執行權力,然后在命令行上指定腳本的路徑運行;或是直接運行解釋器,將腳本作為解釋器的參數運行。

了解shell腳本編程,我們先要了解其一些基本的組成或涉及的基本內容。由于涉及內容較多,一些部分可能不會詳細講解。

 

變量

學習Shell腳本離不開變量,根據生效范圍變量主要分為;

局部變量:只對當前shell進程有效;對當前shell之外的其它shell進程包括其子shell均無效。在函數中用local聲明的局部變量只能用在函數中。

環境變量:當前shell進程及其子進程有效。

變量賦值

局部變量 VAR_NAME=value 或declare VAR_NAME=value

環境變量 export name=value 或declare -x name=value

顯示所有環境變量可以用命令:export或env

只讀變量 readonly name=value 或 delcare -r name=value

聲明后不能修改和刪除。

刪除變量 unset name

顯示已定義的所有變量 set或declare

變量引用 $name;${name}

shell 會對雙引號內的美元符號后的變量執行變量擴展,對于單引號內的則不會。

 

命令替換

Linux命令的輸出可以被賦給一個變量,或者通過使用反引號引用命令,在一個字符串中使用該命令的輸出。Bash還提供了另一中新語法:無需反引號,只將命令包含在由美元符號開始的一對圓括號中即可。即:

    variable_name=`COMMAND`

    variable_name=$(COMMAND)

范例

Bash shell 腳本編程全攻略(上篇) 

 

數組

Bash中可以創建一維數組。數組允許將一列詞放到一個變量名中,例如一列數、一列名稱或一列文件。


數組聲明(賦值)

數組可以用內置命令decare -a來創建,或者直接給變量名一個下標來創建,如arry_name[0]=5。索引值是從0開始的整數。

如果declare命令帶-a和-r選項,將創建一個只讀數組。

也可以一次性給全部或部分元素賦值,如:

    arry_name=("apple pie" banana  cat )此時索引從0開始,按序關聯。

    arry_name=([0]="apple pie" [2]=cat )

declare,readonly,和local內置命令也可以帶-a選項來聲明一個數組,-a選項的read命令用來從標準輸入讀入一組詞到數組元素中。

 

關聯數組

數組沒有上限,索引不必連續(稀疏格式)。還可以使用自定義的模式,如declare -A arry_name=([a]=apple [b]=banana),稱為關聯數組,此時必須用decare -A來聲明賦值才能用。

 

數組引用

要取出數組中的一個元素:${arry_name[index]}。

引用數組中的所有元素:${arry_name[*]}或${arry_name[@]}

數組切片 ${arry_name[@]:offset:num}。

    eg.  ${arry1[@]:1:3} 跳過第一個,取之后的3個元素。

 

數組長度(元素個數)

    ${#arry_name[*]}或${#arry_name[@]}

 

數組刪除

    刪除整個數組:unset arry_name

    刪除單個元素:unset arry_name[index]

 

Shell讀取用戶輸入之read

read是一個內置命令,用于從終端或文件讀取輸入。read命令讀取一個輸入行,直至遇到換行符。如果read后未跟變量,讀入的行將會賦給內置變量REPLY。也可以用read命令來中斷程序的運行,直至用戶輸入一個回車鍵。read常用方法與選項為:

read answer

從終端讀入一行賦值給變量answer

read first…last

把用戶鍵入的詞依次賦給賦給變量fist…,剩余的部分全部保存到變量last中

read -p promt

打印提示符,并等待用戶輸入

-a arryname

讀入一組詞,以此賦值給數組arryname

-t timeout

等待用戶輸入時間,如果在timeout(sec)時間沒有輸入一個完整的行則退出并返回一個失敗狀態值。

范例

Bash shell 腳本編程全攻略(上篇) 

 

位置參量與命令行參數

用戶可以通過命令行向腳本傳遞參數,我們用位置參量(或稱為位置變量)來引用。例如:$1代表第一個位置參量。位置參量有:

$0

腳本名(腳本路徑)

$1…${10}

單獨的位置參量

$#

位置參量個數

$*

所有參數,全部參數合為一個字符串

$@

所有參數,全部參數分為單獨字符串;$*與$@在加雙引號時才有區別

帶參數的set命令將重置位置變量,且原來的參量列表就丟失了。要清除所有位置參量,可使用set –,$0始終代表腳本名。

范例:腳本如下

#!/bin/bash

echo $1

echo $2

echo $3

echo ====

for i in $*;do

        echo $i

done

echo ====

for i in $@;do

        echo $i

done

echo ====================

for i in "$*";do

        echo $i

done

echo ====

for i in "$@";do

        echo $i

done

set 1 2 3

echo $1

echo $2

echo $3

set —

echo \$1 is $1

執行結果

Bash shell 腳本編程全攻略(上篇) 

說明:輸入3個腳本參數"blue sky”green white給腳本test。

 

算術運算

Shell腳本少不了算術運算。

可以用declare -i定義一個整型變量,如果把一個整型變量賦值給一個字符串,則bash把變量值變為0。

整型變量可以進行直接進行算術運算;內置let命令也允許進行算術操作,且帶有豐富的類C操作符,雙括號(( ))是let的另一種可選形式。

范例:

Bash shell 腳本編程全攻略(上篇) 

說明:整型變量直接運算時,中間不能有空格,或者用雙引號括起來。

let命令是shell的內置命令,可以用來進行整數運算和數值表達式測試。

范例:

Bash shell 腳本編程全攻略(上篇) 

說明:let執行算術運算時,不需要用美元符號$展開變量;如果參數包含空格則需要加引號;雙括(( ))可以代替let變量,此時操作符之間可以有空格。let操作符有:

+  –  *  /

加(正號)、 減(負號)、 乘、 除

%

余數(取模)

!

邏輯非

按位取反

<<  >>

按位左移 、 按位右移

<  >  <=  >=

關系運算符,小于、 大于、 小于等于、 大于等于

==  !=

相等 、不相等

&  |  ^

按位與 、按位或、按位異或

&&  ||

邏輯與 、邏輯或

=  *=  /=  %=  +=  -=  <<=  >>=

&=  ^=  |=

賦值、快捷賦值運算符


算術擴展

Shell通過對一個算術表達式求值并替換結果來進行算術擴展。表達式可以像在雙引號中一樣來處理,并且可以嵌套。求值算術表達式有以下兩種格式:

    $[ expression ]  

    $(( expression ))

范例:

Bash shell 腳本編程全攻略(上篇) 

因也可以把$[ ]當作算術運算的另一種方法。

當執行變量、命令、算術表達式和路徑名的擴展時,shell被設計按照指定的順序來掃描命令行。假設變量沒有被引用,處理就將按下面的順序進行。

1、花括號擴展2、代字符號擴展3、參量擴展4、變量替換5、命令替換6、算術擴展7、詞分離8、路徑名擴展


expr命令

算術運算還可以采用一種方法:expr命令。expr命令用來求表達式的值,其中便包括部分算術運算。

范例

Bash shell 腳本編程全攻略(上篇) 

說明:用expr時各符號間需要空格隔開,乘號需要加反斜桿轉義。


浮點運算

Bash只支持整型運算,但也可以一些其他工具如bc,awk來處理更復雜的運算。

范例

Bash shell 腳本編程全攻略(上篇) 

說明:用echo將表達式通過管道傳遞給bc,scale變量等于3表示小數點后面為3位小數。

 

條件測試

Bash可以測試兩種類型的條件:命令成功或失敗,表達式為真或為假。在任何一種類型的測試中都要使用退出狀態。退出狀態為0表示命令執行成功或表達式為真,非0表示命令執行失敗或表達式為假。狀態變量“?”中保存的是退出狀態值。


條件測試之test與let

單方括號的test命令    通常內置的test命令來測試表達式的值,test命令也可以鏈接到方括號上。這樣,既可以使用單獨的test命令,也可以通過把表達式用單括號括起來,來測試表達式的值。在用test命令或單方括號來測試表達式時,表達式中的shell元字符不會被擴展。由于要對變量進行單詞分離,因此包含空白字符的字符串必須用引號括起來。

雙方括號的test命令    用雙方括號[[ ]](內置的test復合命令)來測試表達式的值時,對變量不進行單詞分離,但可以通過元字符擴展進行模式匹配。包含空白字符的字符串必須用引號括起來。此時邏輯操作符&&(與)和||(或)代替了與test命令一起使用的-a和-o選項。

test命令操作符(除&&和||外,其他操作符兩邊及中括號兩邊都須有空格):

操作符

測試內容

字符串測試

[ string1 = string2 ]

string1等于string2

[ string1 == string2 ]

string1等于string2(可用=代替)

[ string1 != string2 ]

string1不等于string2

[ string ]

string不為空

[ -z string ]

string的長度為0

[ -n string ]

string的長度不為0

邏輯測試

[ string1 -a string2 ]

string1和string2都為真

[ string1 -o string2 ]

string1或string2至少有一個為真

[ ! string ]

字符串不匹配

邏輯測試(復合命令)

[[ pattern1 && pattern2 ]]

pattern1和pattern2都為真

[[ pattern1 || pattern2 ]]

pattern1和pattern2至少有一個為真

[[!pattern ]]

模式不匹配

[[ pattern1 =~ pattern2 ]]

pattern1是否與pattern2匹配(正則表達式匹配)

整數測試

[ int1 -eq int2 ]

Int1等于int2

[ int1 -ne int2 ]

Int1不等于int2

[ int1 -gt int2 ]

Int1大于int2

[ int1 -ge int2 ]

Int1大于或等于int2

[ int1 -lt int2 ]

Int1小于int2

[ int1 -le int2 ]

Int1小于或等于int2

文件測試

[ file1 -nt file2 ]

文件file1比file2新則為真

[ file1 -ot file2 ]

文件file1比file2老則為真

[ file1 -ef file2 ]

文件file1和file2有相同的設備數或i節點數則為真

[ -e file ]

文件是否存在(同-a);此外還有許多文件測試,如

-r/-w/x;-g/-u/-k;-t/-N/-O/-G;

-b/-c/-d/-f/-h(-L)/-p/-s/-S(socket)

范例

Bash shell 腳本編程全攻略(上篇) 

說明:單方括號是test的另一種表示方法,test命令不允許使用通配符,所以單方括號中[LI]不會被展開,linux與[Ll]inux不相等,返回狀態為1;當使用復合test命令時可以使用通配符,返回值為真。

Bash shell 腳本編程全攻略(上篇) 

說明:雙方括號的復合test,此時支持通配符,不進行變量分離;等號加波浪符(=~),則為正則表達式模式匹配。邏輯操作符用&&代替-a。


let命令和帶雙圓括號的算術表達式測試

雖然test命令可以測試算術表達式,但由于let命令豐富的類C操作符,我們更愿意使用let命令,此時將表達式放在雙圓括號來表示不同含義。

范例

Bash shell 腳本編程全攻略(上篇) 

說明:雙圓括號代替let命令來測試算術表達式里的值,此時括號里的變量不需要使用美元符號$展開。

 

條件語句

條件語句之if

條件語句能夠根據某個特定的條件是否滿足,來選擇執行相應的任務。if是最簡單的決策形式。if/else語句提供雙分支,而if/elif/else語句則提供多分支。

if語句后加一條后面跟一條或一組命令引用或測試表達式,如果該命令或測試表達式的退出狀態為0,則執行then到fi之間的語句;如果退出狀態為非0,則shell直接跳到fi后面執行命令。雙路決策則為退出狀態為0則執行then到else之間的語句;否則執行else到fi之間的語句。同理多分支則再次提供一次或多次測試。

if語句格式

Bash shell 腳本編程全攻略(上篇) 

詳細為:

單分支

if condition;then

COMMANS(命令組)

fi


雙分支

if condition;then

COMMANS(命令組)

else

COMMANS(命令組)

fi


多分支

if condition;then

COMMANS(命令組)

elif condition2;then

COMMANS(命令組)

else

COMMANS(命令組)

fi

條件conditon可為命令、test測試表達式或則雙圓括號的算術表達式(( ))。

關鍵字之間的命令采用縮進格式,是一種慣例,以使程序便于閱讀和調試。

if語句可以嵌套,如果嵌套使用if語句,fi總是與最近的if語句配套。同理最好對嵌套if語句進行縮進。

范例:

Bash shell 腳本編程全攻略(上篇) 

說明:反向單引號引用grep命令在/etc/passwd文件中查找$name,由于不需要看grep命令的輸出結果,所以用標準錯誤輸出和標準輸出都重定向到linux的位容器/dev/null中。

grep命令若找到了$name則退出狀態返回0,就執行then后面的語句,否則執行else后面的語句。exit 1顯示退出狀態1,說明查找失敗。


exit命令和變量"?"

exit命令用于終止腳本并返回命令行。傳遞給exit的參數是一個0~255之間的整數。如果程序返回退出狀態0,則表示程序成功退出。否則表示遇到了某種失敗。傳遞給exit的參數保存在變量"?"中。腳本程序默認的退出狀態是程序最后一條命令的執行狀態。

 

null命令

冒號(:)代表的null命令是shell的一個內置命令,它不做任何工作,只返回退出狀態0。null命令有時被放在if后作為一個占位符,這時if命令沒有什么事可做,卻需要有一條命令放在then后面,否則程序會產生報錯信息。null命令常常被用作循環命令的參數,作用是讓循環無限執行下去。

 

條件語句之case

case命令是一個多路分支命令,可用來代替if/elif命令。case變量的值與value1,value2等的值逐一比較,知道找到與之匹配的值。如果某個值與case變量匹配,程序就執行該值后面的命令,直到遇到雙分號,然后跳到esac后面繼續往下執行。

如果沒有找到與case便來那個匹配的值,程序就執行默認值"*)"后面的命令,然后跳出。case的表達式里可以用shell通配符,還可以用豎桿將兩個值相或。

格式

Bash shell 腳本編程全攻略(上篇) 

詳細

case 變量 in

value1)

COMMANDS

;;

value2)

COMMANDS

;;

*)

COMMANDS

;;

esac

范例

Bash shell 腳本編程全攻略(上篇) 

說明:提示用戶輸入一個選擇存入變量choice中,如果choice的值與下面的選項某項匹配則執行相應的命令。


用here文檔和case語句生成菜單

here文檔經常與case命令結合起來使用。我們可以用here文檔生成一個選項菜單顯示在屏幕上,要求用戶選擇一個菜單項,然后用case命令對照選項測試用戶的輸入以執行相應的命令。

Bash shell 腳本編程全攻略(上篇) 

說明:cat生成here文檔,read讀入用戶的輸入保存在choice變量中,其值與那個選項匹配便執行相應的命令。

原創文章,作者:beyond,如若轉載,請注明出處:http://www.www58058.com/40785

(1)
beyondbeyond
上一篇 2016-08-29 08:44
下一篇 2016-08-29 08:45

相關推薦

  • 關于shell腳本基礎編程第五篇

                  shellb編程基礎第五篇              本章內容:數組 變量:存儲單個元素的內存空間數組:存儲多個元素的連續的內存空間…

    系統運維 2016-08-24
  • Linux無人值守安裝

    前言     通常情況下,我們安裝Linux操作系統的時候需要從光盤啟動,通過系統光盤bootloader啟動安裝程序,進入交互式安裝模式,由用戶配置安裝選項,如磁盤分區、選擇安裝包等操作;安裝完畢后重啟結束安裝。在生產環境中,成百上千臺服務器需要安裝操作系統的時候如果也采用交互式安裝模式,無疑是極其低效的。本文主要介…

    Linux干貨 2015-05-18
  • 運維自動化之系統安裝

    自動化安裝系統,cobbler的安裝使用

    Linux干貨 2018-01-15
  • ?Linux 硬連接與軟連接的區別

        Linux 硬連接與軟連接的區別                        &…

    Linux干貨 2016-10-25
  • Linux文本處理三劍客之grep

    一、grep命令 grep(global search regular expression(RE) and print out the line,全面搜索正則表達式并把行打印出來 作用:文本搜索工具,根據用戶指定的“模式”對目標文本逐行進行匹配檢查;打印匹配到的行。 模式:由正則表達式字符及文本字符所編寫的過濾條件 二、grep命令格式 grep [OPT…

    Linux干貨 2016-08-15
  • ls的常用用法

    第一個命令

    2018-03-26
欧美性久久久久