天天看點

bash腳本總結

bash及shell腳本程式設計基礎

bash特性之多指令執行:使用分号分隔,指令之間無關系;

]# cmd

方式一:]# cmd1 `cmd2`:指令引用實作多指令;

方式二:]# cmd1|cmd2|cmd3|...:管道實作多指令;

方式三:]# cmd1;cmd2;cmd3;...:分号實作多指令;

邏輯組合:操作的是指令的運作狀态結果即退出碼;

]# cmd1 && cmd2 && ...

]# cmd1 || cmd2 ||...

]# !cmd1

退出碼:

0:表示為true,真,success,成功;

1-255:表示為failure,假,錯誤;

邏輯運算:主要操作的是指令的運作狀态結果即退出碼;

可認為有一種判斷的機制在裡面;判斷取決于是與運算還是或運算還取決于第一個操作的結果;

運算數:true(1),false(0)

COMMAND運作狀态結果:

0:TRUE,成功;

1-255:FALSE,錯誤;

與:見false(0)為false(0);相當于乘法;

true && true = true

true && false = false

第一個操作數為true,其結果取決于第二個操作數;

false && true = false

false && false = false

第一個操作數為false,其結果至此可判定為false;

例如:

]# ls /var && cat /etc/fstab

]# lls /var && cat /etc/fstab

或:見true(1)為true(1);相當于加法;

true || true = true

true || false = true

第一個操作數為true,其結果至此可判定為ture;

false || true = true

false || false = false

第一個操作數為false,其結果取決于第二個操作數;

]# id hive || useradd hive:如果使用者不存在,則添加使用者;

]# id hive

非:取反

! true = false

! fase = true

]# ! id hive && useradd hive:如果使用者不存在,則添加使用者;

優先級:非 (高)<--與 <--或(低)

運作腳本:

(1)賦予執行權限,并直接運作此程式檔案;

chmod +x /PATH/TO/SCRIPT_FILE

/PATH/TO/SCRIPT_FILE

也可直接把腳本檔案放在PATH環境變量中;例如把腳本檔案放在/bin目錄下;

(2)直接運作解釋器,以腳本檔案為參數;

bash /PATH/TO/SCRIPT_FILE

-x:調試執行;

-n:判斷文法錯誤;

bash特性之變量:

引号有三種類型:'',"",``

引号:字元串引用符号;

''單引号:強引用;其内部的變量不會替換;

""雙引号:弱引用;其内部的變量會被替換;

``反引号:指令引用符号;

]# echo '$PATH'

顯示結果:$PATH

]# echo "$PATH"

顯示結果:/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

]# echo `ls /root`

顯示結果:anaconda-ks.cfg install.log install.log.syslog

變量引用:${NAME},要使用花括号

變量:是記憶體空間,有名稱,名稱即為變量名,對應的記憶體空間中的資料即為變量的值;

變量指派:NAME=VALUE

=:指派符号;

把VALUE存儲到NAME指向的記憶體空間中;

程式設計語言:

強類型:嚴格區分變量(記憶體空間)中的資料類型;

弱類型:不區分變量中存儲的資料類型,統一為字元型;

bash:統統預設為字元型資料,變量無需事先聲明;

變量為什麼有類型?

存儲空間、存儲格式、參與的運算、...

變量命名:隻能使用字母、數字和下劃線;且不能以數字開頭;

變量名:見明知義,不能使用程式保留字(如if,then,case,fi,esac,for,while,until,break,continue等等);

變量引用:${NAME},$NAME

變量替換:把變量引用符号出現的位置替換為其指向的記憶體空間中的資料;

bash的變量種類:

根據作用域劃分:作用域:生效範圍,可引用到的範圍;

變量目的:

(1)變量用于存資料,可重複多次使用這個資料;

(2)可多次修改變量裡面的資料,以達到演進、疊代目的;

本地變量

環境變量

局部變量(函數中)

位置參數變量:

特殊變量:$?,, $@, $#

retval=$?

儲存的是指令執行的狀态結果;

exit結束shell程序;

pstree指令:顯示程序樹;

tree指令:顯示目錄樹;

本地變量:作用域為目前shell程序;不包括其子程序;

定義本地變量:

本地變量指派:NAME=VALUE

本地變量引用方式:$NAME,${NAME}

""

檢視變量:set

撤銷變量:unset NAME

注意:此處非為變量引用,是以不能使用$;

所有的本地變量在shell程序終止時,會被自動撤銷;

]# pstree:檢視shell程序樹;

]# name="obama":定義本地變量;僅目前shell程序有效;

]# echo $name

切換到另外的程序檢視name變量:

]# echo $name:内容為空;本地變量在同級程序或子程序都無效;

]# set:檢視本地變量;

]# unset name:撤銷本地name變量;此處非為變量引用,是以不能使用$;

]# animal="goat"

]# echo "There are some $(animal)s."

環境變量:作用域為目前shell程序及其子程序;但不包括同級程序;

環境變量聲明和指派:

declare -x NAME[=VALUE]

-r:定義為隻讀變量;

export NAME[=VALUE]

可以把本地變量聲明環境變量;

環境變量引用方式:

${NAME},$NAME

注意:bash内嵌了很多環境變量,名稱為全大寫字母;例如:HOME,UID,PWD,SHELL,PATH,HISTSIZE等等;

主要用于工作的特殊環境;

檢視環境變量指令:

export,declare -x

env,printenv

撤銷環境變量:

unset NAME

]# declare -x animal:聲明環境變量;

]# /bin/bash:環境變量在目前shell程序及其子程序有效;

]# echo ${animal}:花括号可省略;

]# export:檢視環境變量;

]# declare -x:檢視環境變量;

]# env:檢視環境變量;顯示格式不同;

]# printenv:檢視環境變量;顯示格式不同;

]# unset namimal:撤銷環境變量;

]# ls /etc

]# retval=$?:把環境變量的值存儲在變量中,友善使用;

]# lll /etc

]# echo $?:檢視環境變量狀态傳回值;

]# echo $retval:檢視之前的環境變量狀态傳回值,這就是變量的意義;  

隻讀變量:就是常量,無法修改,無法撤銷;生命周期同目前shell;

定義隻讀變量:不支援重新指派,也不支援撤銷;

(1)declare -r NAME

(2)readonly NAME

]# username="Lu Youjiao"

]# declare -r username:定義隻讀變量;

]# username="Ou Yangfeng":顯示不能更改隻讀變量;

]# unset username:無法撤銷隻讀變量;

bash腳本程式設計之算術運算

+,-,*,/,%(莫,判斷單雙數),**

shell變量是一種很弱的變量,預設情況下,一個變量儲存一個串,shell不關心這個串是什麼含義,是以弱要進行數學運算,必須使用一些指令例如let,declare,expr,雙括号等;

算術運算

+,-,*,/,%(取模,判斷單雙數),**

算術運算格式文法:

(1)let VAR=$num1 op $num2(算術運算表達式)

(2)VAR=$[算術運算表達式]

(3)VAR=$((算術運算表達式))

(4)VAR=$(expr argu1 argu2 argu3)

注意:有些時候乘法符号需要轉義;

練習:腳本完成,添加3個使用者,求三使用者的ID之和;

id user1 &> /dev/null || useradd user1

id user2 &> /dev/null || useradd user2

user1_id=$(id -u user1)

user2_id=$(id -u user2)

id_sum=$[$user1_id+$user2_id]

echo "the id sum: $id_sum"

增強型變量指派:

+=,-=,*=,/=,%=

自身等于自身+數值,使用let指令;

    ]# declare -i i=1    

    ]# i=$[$i+1]                           

    ]# echo $i

此時就可用增強型指派:

    ]# let i+=1

變量做某種算術運算後回存至此變量中;

    let i=$i+#

    let i+=#

    #:代表數字

自增:

    VAR=$[$VAR+1]

    let VAR+=1

    let VAR++

自減:

    VAR=$[$VAR-1]

    let VAR-=1

    let VAR--

練習:

1、腳本實作,計算/etc/passwd檔案中第15個使用者和第18個使用者的ID号之和;

分解:做a,b2個id号的運算,id_sum=$[$id1+$id2]

 a=$(head -15 /etc/passwd | tail -1 | cut -d: -f3)

 b=$(head -18 /etc/passwd | tail -1 | cut -d: -f3)

 sum=$[$a+$b]

 echo "the a is:$a"

 echo "the b is :$b"

 echo "teh sum is :$sum"

2、計算/etc/rc.d/init.d/functions和/ect/inittab檔案中的空白行數之和;

a=$(egrep "^[[:space:]]*$" /etc/rc.d/init.d/functions|wc -l)

b=$(egrep "^[[:space:]]*$" /etc/rc.d/init.d/network|wc -l)

sum=$[$a+$b]

echo "a is :$a"

echo "b is $b"

echo "sum is :$sum"

bash腳本程式設計之條件測試:

判斷某需求是否滿足,需要由測試機制來實作;

如何編寫測試表達式以實作所需的測試:

例如:判斷某檔案是否有空白行、判斷某使用者是否存在

(1)執行指令,并利用指令狀态傳回值來判斷;

0:成功

1-255:失敗

$?:存儲上一條指令執行狀态傳回值;

判斷使用者centos是否登入系統:

    who|grep "^centos\>"

    echo $?:顯示上一個指令狀态傳回值;

取得指令狀态傳回值,0表示登入,1-255表示沒登入;

(2)測試表達式

test EXPRESSION

[ EXPRESSION ]

` EXPRESSION `

字元比較時,用雙中括号

注意:EXPRESSION兩端必須要有空白字元,否則文法錯誤;

bash腳本程式設計之測試類型:

數值測試

字元串測試

檔案測試

數值測試:數值之間的比較

-eq:是否等于;例如:[ $num1 -eq $num2 ],test 2 -eq 3或[ 2 -eq 3 ]

-ne:是否不等于;

-gt:是否大于;

-ge:是否大于等于;

-lt:是否小于;

-le:是否小于等于;

]# test 2 -gt 3

]# [ $A -eq $B ]

centos使用者id是否比ubuntu使用者的ID大?

 a=$(id -u centos)

 b=$(id -u ubunto)

 [ $a -gt $b ] && echo "centos is bigger" || echo "ubuntu is bigger"

字元串測試比較

==:是否等于,等于為真;

!=:是否不等,不等于為真;

>:是否大于,大于為真;

<:是否小于,小于為真;

=~:左側字元串是否能被右側的PATTERN所比對(左邊是否包含右邊),包含為真;

]# name=uubuntuu

]# [[ "$naem" =~ buntu ]]

]# echo $?

判斷主機名是否包含magedu,如果不包含,則修改為magedu;

  ]# a=$(hostname)

  ]# [[ "$name" =~ magedu ]] || hostname magedu

字元串是否為空:  

-z "STRING":判斷指定的字元串是否為空;

空則為真,不空則為假

-n "STRING":判斷指定的字元串是否不空;

不空則為真,空則為假;

注意:

(1)字元串比較要加引号,表示引用;即不做變量替換可用單引号,做變量替換要用雙引号;

(2)字元串比較時,要使用` `雙中括号;            

主機名如果為空,或者為localhost.locadomain或者包含localhost或者包含linux則統統将其設為www.magedu.com

]# [ -z "$name" -o "$name"=="localhost.locadomain" -o "$name"=~"localhost" -o "$name"=~"linux" ] && hostname www.magedu.com

注意:使用-o邏輯時,字元測試比較符不能有空格且字元要用引号,不能用雙中括号。

檔案測試:

存在性測試

-a FILE

-e FILE:檔案的存在性測試,如果存在,則為真;

]# [ -e /etc/passwd ]

檔案的存在性及檔案類型測試:既能測試存在性又能測試類别

-b FILE:檔案是否存在并且為塊裝置檔案;

-c FILE:檔案是否存在并且為字元裝置檔案;

-d FILE:檔案是否存在并且為目錄檔案;

-f FILE:檔案是否存在并且為普通檔案;

-h FILE或-L FILE:檔案是否存在并且為符号連結檔案;

-p FILE:檔案是否存在并且為命名管道檔案;

-S FILE:檔案是否存在并且為套接字檔案;

]# [ -c /dev/null ]

檔案權限測試:

-r FILE:檔案是否存在并且對目前使用者可讀;

-w FILE:檔案是否存在并且對目前使用者可寫;

-x FILE:檔案是否存在并且對目前使用者可執行;

[ -w /etc/passwd ] && echo ok

特殊權限測試:

-u FILE:檔案是否存在并且擁有SUID權限;

-g FILE:檔案是否存在并且擁有SGID權限;

-k FILE:檔案是否存在并且擁有sticky權限;

[ -u /usr/bin/passwd ]

檔案是否有内容:

-s FILE:是否有内容,有則為真:

[ -s /etc/fstab ]

檔案時間戳是否變化:

-N FILE:檔案自從上一次讀操作之後,是否被改過;

檔案從屬關系測試:

-O FILE:目前使用者是否為檔案的屬主;

-G FILE:目前使用者是否為檔案的屬組;

雙目測試:

FILE1 -ef FILE2:檔案1與檔案2是否指向同一個檔案系統上相同inode的硬連結;

FILE1 -nt FILE2:檔案1是否新于檔案2;

FILE1 -ot FILE2:檔案1是否舊于檔案2;

組合測試條件:

邏輯運算:

第一種方式:

COMMAND1 && COMMAND2:與運算;

COMMAND1 || COMMAND2:或運算;

! COMMAND(取反)

[ -O FILE ] && [ -r FILE ]

第二種方式:

expresssion1 -a expression2

expresssion1 -o expression2

! expresssion或-not expresssion

[ -O FILE -a -x FILE ]:目前引用是否為file檔案的屬主,且是否有執行權限;

練習:将目前主機名稱儲存至hostName變量中;

主機名如果為空,或者為localhost.localdomain,則将其設定為www.magedu.com;

hostName=$(hostname)

[ -z "$hostName" -o "$hostName"=="localhost.localdomain" -o "$hostName"=="localhost" ] && hostname www.magedu.com

腳本的狀态傳回值:

預設是腳本中執行的最後一條指令的狀态傳回值;

自定義狀态退出狀态碼;

exit [n]:n為自己指定的狀态碼;

    注意:shell程序遇到exit時,即會終止,是以,整個腳本執行即為結束;

是以,exit不能随意添加使用,要使用條件測試判斷後,确定是否添加exit退出;

埋點調試;使用$?能判斷是在哪個位置退出的,定位問題常用;

腳本實作,一行指令實作,magedu使用者是否存在,不存在,則添加,如果存在,以狀态碼為5的方式退出;

id mageedu &> /dev/null || useradd mageedu && exit 5

或:id mageedu &> /dev/null && exit 5 || useradd mageedu

bash腳本程式設計之向腳本傳遞參數

位置參數變量

指令行:*.sh argu參數1 argu參數2 argu參數3...

腳本裡引用方式:$1 $2 $3...

myscript.sh agru1 argu2...

引用方式:

    $1:儲存argu參數1;

    $2:儲存argu參數2;

    ...

    ${10},${11}...

輪替:

    shift [n]:位置參數輪替,n為數字預設為1;表示為一次輪替前幾個參數;

$1,$2...就叫位置參數變量,每次運作腳本時,通過傳遞參數變化來改變這些參數變量的值;

my_shell.sh ubuntu centos linux

腳本中使用$1,$2,$3

useradd $1

useradd $2

useradd $3

解釋:$1=ubuntu,$2=centos,$3=linux

shift #:表示删掉指定參數;把後面的參數往前補充;

腳本實作,通過指令傳遞兩個文本路徑給腳本,計算其空白行數(^$)之和;

a=$(egrep "^$" $1|wc -l)

b=$(egrep "^$" $2|wc -l)

shift #:會自動踢出指令參數;

特殊變量:

$0:儲存腳本檔案路徑本身;

$#:儲存腳本參數的個數;

$*:儲存所有參數;把每個參數當做一個個獨立參數顯示;

$@:儲存所有參數;把每個參數合在一起,當做一個字元串參數顯示;

$0:表示指令行給定腳本檔案路徑;

例如:指令行]# bash /tmp/parameter_blanksum.sh

腳本内容:echo $0

顯示結果為:/tmp/parameter_blanksum.sh

如果指令行是:bash parameter_blanksum.sh

腳本内容不變,顯示結果為:parameter_blanksum.sh

$#:表示腳本參數的個數;

]# bash parameter_blanksum.sh /etc/init.d/functions /etc/init.d/network

腳本内容:echo $#

顯示結果為:2

$*:表示參數為多個字元串;

$@:表示參數為一個字元串;

例如:指令行]# bash parameter_blanksum.sh /etc/init.d/functions /etc/init.d/network

腳本内容:echo $*

      echo $@

顯示結果為:/etc/init.d/functions /etc/init.d/network

/etc/init.d/functions /etc/init.d/network

但是$*表示為2個分開的路徑,而$@表示為一整行為一個字元串。

1、判斷/etc/passwd是否為檔案,如果為檔案,則輸出/etc/passwd is files,該路徑通過指令傳遞的方式傳入,當傳入的指令個數大于1,則報錯;

[ $# -gt 1 ] && echo "something wrong " && exit 100

[ -f $1 ] && echo "/etc/passwd is files"

2、在root目錄下,寫腳本,可以一次性添加3名使用者,通過傳遞參數的方式,進行使用者添加,當傳遞的參數不符合3個的時候,報錯;

當三名使用者添加完成後,需要将腳本進行權限加強(鎖機制,不能再執行),将腳本權限改成屬主可讀可寫可執行;

! [ $# -eq 3 ] && echo "please give me three username" && exit 1

useradd $1 && a=1

useradd $2 && b=1

useradd $3 && c=1

sum=$[$a+$b+$c]

[ $sum -eq 3 ] && echo "$1 $2 $3" ||exit 2

chmod 700 $0

echo $1 is added

echo $2 is added

echo $3 is added

echo "this scripts mode is 700"

或:

[ $# -gt 3 ] || [ $# -lt 3 ] && echo "something wrong,give three user" && exit 1

 id $1 &> /dev/null && echo "$1 exist" || useradd $1

 id $2 &> /dev/null && echo "$2 exist" || useradd $2

 id $3 &> /dev/null && echo "$3 exist" || useradd $3

echo "three users $1,$2,$3 are added success"

echo "this script mode is 700"

過程式程式設計語言的代碼執行順序:

順序執行:逐條運作;

選擇執行:

代碼存在一個分支:條件滿足時才會執行;

兩個或以上的分支:隻會執行其中一個滿足條件的分支;

循環執行:

某代碼片段(循環體)要執行0、1或多個來回(循環);

順序執行

條件選擇:

(1)&&,||

(2)if語句(單分支,雙分支,多分支)

(3)case語句

循環執行:for,while,until

bash腳本程式設計之if語句選擇分支

條件判斷:

shell執行是順序執行的

選擇分支

單分支的if語句

    if 測試條件;then(如果條件為真,則執行下面語句)

        代碼分支

    fi

    if 測試條件

    then

雙分支的if語句

if 測試條件;then

條件為真時執行的分支

else

條件為假時執行的分支

fi

多分支的if語句

條件為真時候執行的分支

elif 測試條件;then

條件為假時候執行的分支

通過參數傳遞給一個使用者名給腳本,此使用者如果不存在則建立使用者;

if ! grep "^$1\>" /etc/passwd &> /dev/null;then

echo $1|passwd --stdin $1 &> /dev/null

echo "add a user $1 finished"

echo "$1 is exist"

示例:通過參數傳遞一個使用者名給腳本,此使用者不存在時,則添加;(判斷表達方法:一種是指令,另一種是表達式放在中括号中或用test表示,判斷使用者是否存在用id或grep)

~]# vim useradd.sh

    useradd $1

    echo $1 | passwd --stdin $1 &> /dev/null

    echo "add user $1 finished"

~]# ./useradd.sh hbase

執行結果為:add user hbase finished

加入了判斷參數是否存在的判斷if語句:

if [ $# -lt 1 ];then

    echo "at least one username"

    exit 2

變為雙分支判斷if語句:

if grep "^$1\>" /etc/passwd &> /dev/null;then

    echo "user $1 exists"

1、通過指令參數,給定兩個數字,輸出其中較大的數值;

if [ $1 -gt $2 ] ;then

echo $1 is bigger

echo $2 is bigger

if [ ! $# -eq 2 ];then

  echo "give two number"

  exit 2;

if [ $1 -gt $2 ];then

  echo "the bigg is $1"

elif [ $1 -lt $2 ];then

  echo "the bigg is $2"

  echo "$1=$2"

2、通過指令參數,給定兩個文本檔案名,如果某檔案不存在,則結束腳本,如果都存在傳回每個檔案的行數,并echo其中行數較多的檔案名;

[ $# -ne 2 ] && echo "give two file" && exit 1

if ! [ -e $1 ];then

 echo "$1 is not find"

 exit 2

elif ! [ -e $2 ];then

 echo "$2 is not find"

  exit 3

f1=$(cat $1|wc -l)

f2=$(cat $2|wc -l)

 echo "$1 line is $f1"

 echo "$2 line is $f2"

if [ $f1 -gt $f2 ];then

   ehco "$f1 is more"

elif [ $f1 -eq $f2 ];then

  echo "f1 and f2 the same"

  echo "$f2 is more"

if ! [ $# -eq 2 ];then

  echo "give 2 files"

  exit 20;

elif ! [ -e $1 ];then

  echo "$1 is not exist"

  echo " $2 is not exist"

  exit 30;

 f1=$(cat $1|wc -l)

 f2=$(cat $2|wc -l)

echo "f1=$f1"

echo "f2=$f2"

  echo "file1 line is more :$f1"

  echo "$(basename $1) line is more"

elif [ $f1 -lt $f2 ];then

  echo "file2 line is more :$f2"

  echo "$(basename $2) line is more"

  echo "f1-$f1 and f2-$f2 is same"

3、通過指令行參數給定一個使用者名,判斷ID号是偶數還是奇數;

多分支if語句

(2)if語句

if語句:三種格式

if CONDITION;then

if-ture-分支

if-true-分支

if-false-分支

if CONDITION1;then

條件1為真分支

elif CONDITION2;then

條件2為真分支

elif CONDITION3;then

條件3為真分支

...

elif CONDITIONn;then

條件nweizhen分支

所有條件均不滿足時的分支

注意:即便多個條件可能同時滿足,分支隻會執行其中一個,首先測試為真的條件分支執行後,就退出;

示例:通過腳本參數,傳遞檔案路徑給腳本,判斷此檔案的類型;

 echo "at lease one path"

 exit 1

 echo "no such file"

 eixt 2

if [ -f $1 ];then

echo "common file"

elif [ -d $1 ];then

echo "directory file"

elif [ -L $1 ];then

echo "symbolic link file"

elif [ -b $1 ];then

echo "block special file"

elif [ -p $1 ];then

echo "pipe file"

elif [ -S $1 ];then

echo "socket file"

elif [ -c $1 ];then

echo "character special file"

case語句其實就是簡化版的多分支if語句,但未所有if語句都能轉化為case語句;

注意:if語句可以嵌套使用;

1、寫腳本實作如下功能:

(1)傳遞參數給腳本,此參數為使用者名;

(2)根據其id來判斷使用者類型;

0:管理者

1-999:系統使用者

1000+:登入使用者

(3)如不存在,可添加此使用者;

[ $# -lt 1 ] && echo "at least one username" && exit 1

! id $1 &> /dev/null && echo "no such user" && exit 2

userid=$(id -u $1)

if [ $userid -eq 0 ];then

echo "root"

elif [ $userid -ge 1000 ];then

echo "login user"

echo "system user"

2、寫腳本實作如下功能:

(1)列出如下菜單給使用者

disk)show disks info(fdisk -l /dev/sda)

mem)show memory info(free -m)

cpu)show cpu info(使用cat /proc/cpuinfo或lscpu)

*)quit

(2)提示使用者給出自己的選擇,然後顯示對應其選擇的相應系統資訊;

cat << EOF

disk) show disk info

mem) show memory info

cpu) show cpu info

*) QUIT

EOF

read -p "please choice : " option

if [[ "$option" == "disk" ]];then

fdisk -l /dev/[sh]d[a-z]

elif [[ "$option" == "mem" ]];then

free -m

elif [[ "$option" == "cpu" ]];then

lscpu

echo "your choice fault option"

bash腳本程式設計之for循環

循環執行:将一段代碼重複執行0、1或多次;

進入循環條件:隻有條件滿足時才進入循環;

退出循環條件:每個循環都應該有退出條件,有機會退出循環;

bash腳本有三種循環方式:

for循環

while循環

until循環

for循環有2種格式:

(1)周遊清單

(2)控制變量

變量指派有三種方式:

(1)VAR=VALUE,直接指派;

(2)通過read,實作變量指派;

(3)for循環中,用清單指派給變量;

周遊清單:

for VARAIBLE in LIST;do

循環體

done

進入條件:隻有清單有元素,即可進入循環;

退出條件:清單中的元素周遊完成;

LIST的生成方式:

(1)直接給出;

(2)整數清單;

(a){start..end}自動展開;

(b)seq #:從1列出到#的數字;

 seq start end:從開始數字列出到結束數字;

 seq start step end:從開始數字,根據步長,列出結束數字;

seq指令:顯示一系列數字

seq [start [increment]] last

(3)能傳回一個清單的指令;

例如:ls指令

(4)glob通配符機制;

例如:/etc/p*

(5)變量引用

例如:$@,$*

seq 10:列出1 2 3 4 5 6 7 8 9 10

seq 5 10:列出5 6 7 8 9 10

seq 1 2 10:列出1 3 5 7 9

seq 2 2 10:列出2 4 6 8 10

例如:循環添加三個使用者aaa,bbb,ccc;

for username in aaa bbb ccc;do 

if id $username &>/dev/null;then

echo "$username exists"

esle

useradd $username && echo "add user $username finished"

例如:在tmp目錄下建立10個檔案f1-10;

for filename in {1..10};do

  touch /tmp/f$filename

注意:在如何時候,要考慮判斷條件;如上例,應該先判斷檔案是否存在;

例如:求100内所有正整數之和;

declare -i sum=0

for i in {1..100};do

sum=$[$sum+$i]

echo $sum

例如:計算100内的奇數和;

for i in $(seq 1 2 100);do

  sum=$[$sum+$i]

 done

 echo $sum

例如:計算100内的偶數和;

for i in $(seq 2 2 100);do

示例:判斷/var/log目錄下的每個檔案的類型;

file /var/log/*即可判斷,但要求用循環實作;

for filename in /var/log/*;do

 if [ -f $filename ];then

  echo "this is common file"

 elif [ -d $filename ];then

  echo "this is directory file"

 elif [ -L $filename ];then

  echo "this is softlink"

 elif [ -b $filename ];then

   echo "this is block file"

 elif [ -c $filename ];then

  echo "this is character file"

 elif [ -S $filename ];then

  echo "this is socket file"

 elif [ -p $filename ];then

  echo "thisi is pipe file"

 else

    echo "unknow file type"

 fi

1、分别求100内偶數之和,奇數之和;

計算100内的奇數和;

  sum=$[$sum+$i]

計算100内的偶數和;

2、計算目前系統上所有使用者的id之和;

for i in $(cut -d: -f3 /etc/passwd);do

echo "\$sum=$sum,\$i=$i"

3、通過腳本參數傳遞一個目錄給腳本,然後計算此目錄下所有文本檔案的行數之和;并說明此類檔案的總數;

! [ $# -eq 1 ] && exit 1

! [ -d $1 ] && echo "please give a comment file" && exit 2

declare -i filesum=0

declare -i A=0

for i in $(ls $1);do

if [ -f $i ];then

    a=$(wc -l $i|cut -d" " -f1)

    A+=1

    sum=$[$sum+$a]

echo "file line sum=$a,files sum $A,all file line sum is $sum"

else 

echo "this file not text type"  

fi  

for循環格式:

LIST清單生成方式有多種:直接給出,{#..#},或glob(/tpm/test/*)等任何能夠傳回清單的指令都可以;

for循環的特殊用法:

for ((控制變量初始化;條件判斷表達式;控制變量的修正語句)); do

注意:條件判斷可直接使用<,>;

控制變量初始化:僅在循環代碼開始運作時執行一次;

控制變量修正語句:會在每輪循環結束會先進行控制變量修正運算,而後再做條件判斷;

示例:求100内整正數之和

for ((i=1;i<=100;i++));do

        let sum+=$i

echo "sum: $sum"

練習:列印99乘法表

for ((j=1;j<=9;j++));do

        for ((i=1;i<=j;i++));do

                echo -e -n "${i}X${j}=$[${i}*${j}]\t"

        done

        echo

bash腳本程式設計之while循環和until循環

while循環:

while CONDITION;do

循環擴充變量修正表達式(條件修正表達式)

進入條件:CONDITION參數為“真”;

退出條件:CONDITION參數為“假”;

until循環:

until CONDITION;do

進入條件:CONDITION參數為“假”;

退出條件:CONDITION參數為“真”;

until就相當于在while條件前取反(!)的效果;

例如:求100内正整數和;

比for優勢在于,如果數值比較多,for的清單會占用記憶體,while則使用的是變量,占用記憶體空間很小;

for循環:

declare -i i=1

while [ $i -le 10 ];do

    sum=$[$sum+$i]

    let i++ 

until [ $i -gt 100 ];do

    let sum+=$i

練習:分别使用for、while、until各自實作;

1、求100内所有偶數之和、奇數之和;

2、建立10個使用者,分别為user101-user110;密碼同使用者名;

3、列印九九乘法表;

4、列印逆序九九乘法表;

1x1=1

1x2=2,2x2=4

1x3=3,2x3=6,3x3=9

循環嵌套:

外循環控制乘數,内循環控制被乘數;

for j in {1..9};do

for i in $(seq 1 $j);do

echo  -n -e "${i}x${j}=$[${i}*${j}]\t"

echo

進入條件:

for:清單元素非空;

while:條件測試結果為真;

until:條件測試結果為假;

退出條件:

for:清單元素周遊完成;

while:條件測試結果為假;

until:條件測試結果為真;

循環控制語句:

continue:提前結束本輪循環,而直接進入下一輪循環判斷;

while CONDITION1; do

CMD1

if CONDITIONS2; then

continue

CMDn

示例:求100内偶數和;

declare -i evensum=0

declare -i i=0

while [ $i -le 100 ];do

        let i++

        if [ $[$i%2] -eq 1 ];then

                continue

        fi

        let evensum+=$i

echo "evensum : $evensum"

break:提前跳出循環

break

break #:在循環嵌套時,指明跳出哪層循環;

sleep指令:

delay for a specified amount of time

sleep #

#:為數字預設機關是s秒鐘,可用m分鐘,h小時,d天為機關;

建立死循環:

while true;do

退出方式:

某個測試條件滿足時,讓循環體執行break指令;

until false;do

示例:求100内奇數和

declare -i oddsum=0

while true; do

        let oddsum+=$i

        let i+=2

        if [ $i -gt 100 ];then

                break

        fi  

練習:每隔3秒鐘到系統上擷取已經登入的使用者的使用者資訊,其中,如果aaa使用者登入系統,則記錄于日志中,并退出;

        if who | grep "^aaa\>" &>/dev/null;then

        sleep 3

echo "$(date +"%F %T")aaa loggend on " >> /tmp/users.log

或改寫為:

until who |grep "^aaa\>" &>/dev/null;do

echo "$(date +"%F %T") aaa longed on" >> /tmp/user.log

while循環的特殊用法(周遊檔案的行):

while read VARIABLE;do

循環體;

done < /PATH/FROM/SOMEFILE

依次讀取/PATH/FROM/SOMEFILE檔案中的每一行,且将其值指派給VARIABLE變量;

示例:找出ID号為偶數的使用者,顯示器使用者名、ID及預設shell;

while read line;do

        userid=$(echo $line |cut -d: -f3)

        username=$(echo $line |cut -d: -f1)

        usershell=$(echo $line |cut -d: -f7)

        if [ $[$userid%2] -eq 0 ];then

                echo "$username,$userid,$usershell"

done < /etc/passwd

bash腳本程式設計之使用者互動

腳本參數

使用者互動:通過鍵盤輸入資料

read [OPTION] ... [name ...]

-p 'PROMPT':輸出提示符,設定提示資訊;;

-t TIMEOUT:設定逾時退出時間;

name:是在腳本裡設定的變量;

bash -n /path/to/some_script

檢測腳本中的文法錯誤

bash -x /path/to/some_script

調試執行

例如:腳本實作,使用read添加使用者,密碼同使用者名;

read -p "plase give a username and passwd: " a b

useradd $a

echo $a

echo $b

echo "$b "| passwd $a --stdin &> /dev/null

例如:腳本互動,輸入指定使用者名,建立使用者并設定密碼;

read -p "Enter a username: " name

[ -z "$name" ] && ehco " a username is needed " && exit 2

read -p "enter a passwd for $name,[passwd]: " passwd

[ -z "$passwd" ] && passwd="passwd"

if id $name &> /dev/null;then

    echo "$name exists"

    useradd $name

    echo "$passwd " | passwd --stdin $name &> /dev/null

    echo "add user $name finished"

1、判斷給定是兩個數值,誰大誰小

給定數值的方法;指令參數,指令互動

read -p "give two  number: " a b

! [ $# -eq 2 ] && echo "give two number" && exit 1

if [ $a -gt $b ];then

  echo " $a is bigger"

  echo "$b is bigger"

2、提示使用者輸入一個字元串,如果輸入的是quit,則退出,否則顯示其輸入的字元串内容;

read -p "give a string: " a

if ! [ $a == quit ];then

  echo "show string is $a"

  exit 1

3、背景:公司新員工,要開通系統賬号和統計出新員工的資訊(通過互動方式);

讓使用者指定一個使用者名和密碼,如果使用者名之前存在,先進行删除,之後則為使用者添加系統賬号;

完成後,需要統計員工的手機号,email,qq,年齡,收集後存儲到該使用者的家目錄中;

以上完成後,詢問該使用者是否需要給使用者單獨建立一個工作目錄為/data/username,預設是需要,如果不需要,則輸入n或N;

read -p "input a password for useradd: " password

echo $password|passwd  --stdin $username &> /dev/null

echo "user's password is add finished"

read -p "input personal infomation:tel): " tel

echo "$username tel:$tel" >> /home/$username/userinfo.txt

read -p "input personal infomation:email): " email

echo "$username email:$email" >> /home/$username/userinfo.txt

read -p "input personal infomation:qq): " qq

echo "$username qq:$qq" >> /home/$username/userinfo.txt

read -p "input personal infomation:age): " age

echo "$username age:$age" >> /home/$username/userinfo.txt

read -p "you if create personal work DIR (y/n,N)default: y: " dir

if  [ "$dir" == "y" ];then

 mkdir -p /data/$username

elif [ "$dir" == "n" -o "$dir" == "N" ];then

echo "you choice nocreate personal work DIR,bye"

exit 2

bash腳本程式設計之條件選擇case語句

case語句:

if中的多分支in語句:

分支1(CONDITION1為真時執行的語句)

分支2(CONDITION2為真時執行的語句)

else CONDITION;then

分支n

示例:顯示菜單給使用者,

要求:(1)提示使用者給出自己的選擇;

  (2)正确的選擇給出相應資訊,否則,提示重新選擇正确的選項;

cpu) display cpu information

mem) display memory infomation

disk) display disks infomation

quit) quit

==============================

read -p "Enter your choice: " option

while [ "$option" != "cpu" -a "$option" != "mem" -a "$option" != "disk" -a "$option" != "quit" ];do

        echo "cpu,mem,disk,quit,please see "

read -p "Enter your choice again: " option

if [ "$option" == "cpu" ];then

        lscpu

elif [ "$option" == "mem" ];then

        free -m

elif [ "$option" == "disk" ];then

        fdisk -l /dev/[hs]d[a-z]

        echo "quit"

        exit 0

done   

注意:用一個變量與多個值比較時,就可使用case語句替換成if多分支語句;

case語句的文法格式:

case $VARAIBLE in

PAT1)

分支1

;;

PAT2)

分支2

*)

esac

表示變量VARAIBLE與多個模式比較PAT1、PAT2、...,每個分支用雙分号結尾,多分支執行特點是隻要第一個滿足條件,就不執行下面的語句,即使下面的條件也滿足也不執行了;雙分号可單獨成行,也可在分支語句的最後;PAT隻支援glob風格的通配符;僅适用于一般都是變量與PAT做等值比較或模式比對比較時,可替代if多分支語句;

示例:上例用case實作

        echo "cpu,mem,disk,quit,please see "

        read -p "Enter your choice again: " option

case $option in

cpu) 

        lscpu;;

mem) 

        free -m;;

disk)

        fdisk -l /dev/[hs]d[a-z];;

        echo "quit"

        exit 0;; 

case支援glog風格的通配符:

*:任意長度的任意字元;

?:任意單個字元;

[]:範圍内任意單個字元;

a|b:a或b;

示例:腳本實作服務架構(服務腳本不能以.sh結尾)

$lockfile,/var/lock/subsys/SCRIPT_NAME

(1)此腳本可接受start,stop,restart,status四參數之一;

(2)如果參數非此四參數,則提示使用幫助後退出;

(3)start則建立lockfile,并顯示啟動;stop則輸出lockfile,并顯示停止;restart則先删除此檔案再建立檔案,然後顯示重新開機完成;status則如果lockfile操作則顯示running,否則顯示為stopped;

# 下面2語句為服務腳本格式

# chkconfig: - 50 50

# description: test service script

#

prog=$(basename $0)

lockfile=/var/lock/subsys/$prog

case $1 in

start)

        if [ -f $lockfile ];then

                echo "$prog is running yet"

        else

                touch $lockfile

                [ $? -eq 0 ] && echo "start $prog finished"

        ;;

stop)

        if [ $lockfile ];then

                rm -f $lockfile

                [ $? -eq 0 ] && echo "stop $prog finished"

                echo "$prog is not running"

        ;;  

restart)

                rm -f $lcokfile

                echo "restart $prog finished"

                touch -f $lockfile

                echo "start $prog finished"

status)

        if [ -e $lockfile ];then

                echo "$prog is running"

                echo "$prog is stopped"

        echo "Usage :$prog {start|stop|restart|status}"

        exit 1

]# cp exercise.sh /etc/init.d/exercise

]# chkconfig --add exercise

]# chkconfig --list exercise

]# chmod +x /etc/init.d/exercise

服務運作以後都會在/var/lock/subsys/下,建立一個鎖檔案,名稱同服務名稱;

bash腳本程式設計之函數:function(功能)

在過程式程式設計裡:實作代碼重用

子產品化程式設計

結構化程式設計

把一段獨立功能的代碼當做一個整體,并為之取一個名字;命名的代碼段,此即為函數;

注意:定義函數的代碼段不會自動執行,在調用時才執行;所謂調用函數,在代碼中給定函數名即可;

函數名出現的任何位置,在代碼執行時,都會被自動替換為函數代碼;

文法一:

function function_name {

...函數體

}

文法二:

function_name() {

函數的生命周期:每次被調用時建立,傳回時終止;函數也有狀态傳回值,其狀态傳回值預設為函數體中運作的最後一條指令的狀态結果;就像腳本中使用exit #表現為自定義退出狀态結果;而函數用return表示自定義狀态傳回值;

return [0-255]

0:成功;

1-255:失敗;

示例:給定一(或二)個使用者名,取得使用者的ID号和預設shell;

沒用函數:

if id "$1" &> /dev/null;then

        grep "^$1\>" /etc/passwd|cut -d: -f3,7

        echo "no such user"

使用函數:

userinfo() {

        if id "$username" &> /dev/null;then

                grep "^$username\>" /etc/passwd|cut -d: -f3,7

        else

                echo "no such user"

        fi

username=$1

userinfo

username=$2

示例:改寫腳本服務架構(服務腳本不能以.sh結尾)

start() {

        if [ -f $lockfile ];then

                echo "$prog is running yet"

                touch $lockfile

                [ $? -eq 0 ] && echo "start $prog finished"

}      

stop() {

        if [ $lockfile ];then

                rm -f $lockfile

                [ $? -eq 0 ] && echo "stop $prog finished"

                echo "$prog is not running"

}         

restart() {

                rm -f $lcokfile

                echo "restart $prog finished"

                touch -f $lockfile

                echo "start $prog finished"

status() {

        if [ -e $lockfile ];then

                echo "$prog is running"

                echo "$prog is stopped"

usage() {

        echo "Usage :$prog {start|stop|restart|status}"

        exit 1

        start ;;

        stop;;

        stop

        suatus;;

        usage

        exit 1;;

函數傳回值:

函數的執行結果傳回值:

(1)使用echo或printf指令進行輸出;

(2)函數體中調用的指令的執行結果;

函數的退出狀态碼:

(1)預設取決于函數體中執行的最後一條指令的退出狀态碼;

(2)自定義:使用return #

指令都有兩種傳回值,一種為執行結果傳回值,一種為執行的狀态結果傳回值稱為退出狀态碼;在腳本中實作指令替換,指令替換的地方就調用指令執行的結果,函數也一樣,函數替換是調用函數出現的地方,就是函數代碼執行的結果;printf指令:不能換行,但輸出可定義格式化輸出;在awk指令時再介紹;

函數可以接受參數:

傳遞參數給函數:

在函數體中,可以使用$1, $2, ...引用傳遞給函數的參數;還可在函數中使用$*或$@引用所有參數,$#引用傳遞的參數的個數;

在調用函數時,在函數名後面以空白符分隔給定參數清單即可,例如,testfunction arg1 agr2 agr3 ...

示例:添加10個使用者,使用函數實作,使用者名作為參數傳遞給函數;

]# bash -x exercise.sh aaa

addusers() {

        if id $1 &> /dev/null;then

                return 5

                useradd $1

                retval=$?

                return $retval

for i in {1..10};do

        addusers ${1}${i}

        retval=$?

        if [ $retval -eq 0 ];then

                echo "add user ${1}${i} finished"

        elif [ $retval -eq 5 ];then

                echo "user ${1}${i} exist"

                echo "unkown error"

1、腳本函數實作ping主機,來測試主機的線上狀态;

主程式:實作測試172.16.1.1-172.16.67.1範圍内個主機的線上狀态;

分别使用for,while和until循環實作;

普通方式:

declare -i uphosts=0

declare -i downhosts=0

for i in {1..67};do

        if ping -W 1 -c 1 172.16.$i.1 &>/dev/null;then

            echo "172.16.$i.i is up"

            let uphosts+=1

        else    

            echo "172.16.$i.1 is down"

            let downhosts+=1

echo "Up hosts: $uphosts,Down hosts: $downhosts"

改版2:函數+while循環方式:

hostping() {

        if ping -W 1 -c 1 $1 &>/dev/null;then

            echo "$i is up"

            echo "$1 is down"

        fi  

while  [ $i -le 67 ];do

    hostping 172.16.$i.1

    let i++ 

改版3:使用return,在主程式中統計ping的主機數量;

            return 0

             return 1

    [ $? -eq 0 ] && let uphosts++ || let downhosts++

2、腳本函數實作,列印nn乘法表;

變量作用域:

局部變量:作用域是函數的生命周期;在函數結束時被自動銷毀;

定義局部變量的方法:local VARIABLE=VALE

本地變量:作用域是運作腳本的shell程序生命周期;是以,其作用範圍就是目前shell腳本程式檔案;

name=tom

setname() {

name=jerry

echo "Function: $name"

setnaem

echo "Shell: $name"

此時函數的name和shell的name都是jerry,變量name為本地變量,可在函數中調用;

顯示結果為:

Function:jerry

Shell: jerry

如果在以上語句中改為:local name=jerry

Shell: tom

bash腳本程式設計之函數遞歸:

函數直接或間接調用自身;

做階乘或斐波那契數列時會用到函數遞歸;

例如:10!=10*9!=10*9*8!=10*9*8*7!...=10*9*8*7*6*5*4*3*2*1!

函數階乘 傳遞參數為n

n*(n-1)!=n*(n-1)*(n-2)!=...

例如:斐波那契數列

每一個數值都是前2個數的和;求第n階的數是多少就用函數;

1 1 2 3 5 8 13 21 ...

例如:傳遞參數為一個數字,實作數字的階乘;

fact() {

        if [ $1 -eq 0 -o $1 -eq 1 ];then

                echo 1

                echo $[$1*$(fact $[$1-1])]

fact $1

例如:傳遞參數為一個數字,實作斐波那契數列

fab() {

        if [ $1 -eq 1 ];then

                echo -n "1 "

        elif [ $1 -eq 2 ];then

                echo -n "$[$(fab $[$1-1])+$(fab $[$1-2])] "

for i in $(seq 1 $1);do

fab $i

ech

bash腳本程式設計之數組

函數、case語句

case語句文法格式:

case $VARIABLE in

PATTERN:為Glob通配符;

函數:能完成結構化程式設計,實作代碼重用;

function function_name{

函數體

函數定義後,被調用才能執行;

函數調用:給定函數名即可調用,也可給函數傳遞參數,使用位置參數$1,$2,...

局部變量:local VARIABLE

生命周期為調用函數時,函數體内;

數組:

程式=指令+資料

bash腳本中指令:就是整個程式設計中的文法關鍵字,加上各種系統上的指令,加上定義的函數;

資料:存在變量、檔案中、或資料組織結構中;

變量:存儲單個元素的記憶體空間;

數組:存儲多個元素的連續的記憶體空間;

數組名:整個數組隻有一個名字;數組在第一個記憶體空間中存儲的數字就是數組名指向的位置;

數組索引:編号從0開始;引用數組種的資料方式:

數組名[索引]

${ARRAY_NAME[INDEX]}

注意:bash-4及之後的版本,支援自定義索引格式,而不僅是0,1,2,...數字格式;

自定義索引格式的屬組,稱為關聯數組;

聲明數組:

declare -a NAME:聲明索引數組;

declare -A NAME:聲明關聯數組;

檢視聲明幫助:

]# help declare

數組中的資料就是存在記憶體中的一段連續的記憶體空間,分别存儲多個連續的資料,每個資料都是獨立的被管理單元,隻不過沒有獨立的名稱,要通過數組名稱來索引使用,數組名稱加上一個下标可了解為資料在數組中的辨別符;

數組中元素的指派方式:

(1)一次隻指派一個元素:

ARRAY_NAME[INDEX]=value

]# animals[0]=pig

]# animals[1]=cat

]# echo $animals

]# echo ${animals[1]}

(2)一次指派全部元素:

ARRAY_NAME=("VAL1" "VAL2" "VAL3" ...)

會自動指派為0,1,2,3,...

]# weekdays=("Monday" "Tuseday" "Wednesday")

]# echo ${weekdays[2]}

(3)隻指派特定元素;

ARRAY_NAME=([0]="VAL1" [3]="VAL4" ...)

為稀疏格式的數組;

注意:bash支援稀疏格式的數組;

]# sword=([0]="Yitian" [3]="Tulong")

]# echo ${sword[1]}:顯示為空;

]# echo ${sword[3]}:顯示為Tulong;

(4)read -a ARRAY_NAME

]# read -a Linux

sed awk find grep 

]# echo ${Linux[1]}:顯示為awk;

關聯數組:

]# declare -A world:聲明關聯數組;

]# world[us]"America"

]# echo "${world[us]}":顯示為America;

]# world[uk]"unite kingdom"

]# echo "${world[uk]}":顯示為unite kingdom;

引用數組中的元素:${ARRAY_NAME[INDEX]}

注意:引用時,隻給數組名,表示引用下标為0的元素;

${ARRAY_NAME[*]}:引用數組中的所有元素;

${ARRAY_NAME[@]}:同上;

數組的長度(數組中元素的個數):

${#ARRAY_NAME[*]}

${#ARRAY_NAME[@]}

]# echo "${#Linux[*]}:顯示數組元素個數4個;

]# echo "${#animals[@]}:顯示數組元素個數2個;

]# echo "${#animals}:顯示數組第一個元素的字元個數為3個;

]# echo "${animals[*]}:顯示數組中所有元素;可生成清單;

示例:生成10随機數,并找出其中最大值和最小值;

declare -a rand

declare -i max=0

for i in {0..9};do

        rand[$i]=$RANDOM

        echo ${rand[$i]}

        [ ${rand[$i]} -gt $max ] && max=${rand[$i]}

echo "Max: $max"

1、生成10個随機數,由小到達排序;

2、定義數組,數組中的元素是/var/log目錄下所有以.log結尾的檔案;統計其下标為偶數的檔案中的行數之和;

declare -a files

files=(/var/log/*.log)

declare -i lines=0

for i in $(seq 0 $[${#files[*]}-1]);do

        if [ $[$i%2] -eq 0 ];then

            let lines+=$(wc -l ${files[$i]} |cut -d' ' -f1)

echo "lines: $lines"

引用數組中的所有元素:

${ARRAY_NAME[*]}

${ARRAY_NAME[@]}

也可隻傳回有限的幾個元素;

數組元素切片:${ARRAY_NAME[@]:offset:number}

offset:元素偏移量;

number:取元素的個數;省略number時,表示取偏移量之後的所有元素;

]# files=(/etc/[Pp]*)

]# echo ${files[*]}

顯示結果:

/etc/pam.d /etc/passwd /etc/passwd- /etc/pinforc /etc/pkcs11 /etc/pki /etc/plymouth /etc/pm /etc/polkit-1 /etc/popt.d /etc/postfix /etc/ppp /etc/prelink.conf.d /etc/printcap /etc/profile /etc/profile.d /etc/protocols /etc/pulse

]# echo ${files[@]:2:3}:表示從上面的數組中跳過2個,取3個;

/etc/passwd- /etc/pinforc /etc/pkcs11

]# echo ${files[@]:5}

/etc/pki /etc/plymouth /etc/pm /etc/polkit-1 /etc/popt.d /etc/postfix /etc/ppp /etc/prelink.conf.d /etc/printcap /etc/profile /etc/profile.d /etc/protocols /etc/pulse

向非稀疏格式的數組中追加元素:

ARRAY_NAME[${#ARRAY_NAME[*]}]=

${#ARRAY_NAME[*]}]:表示取出數組中的元素個數;

删除數組中的某元素:

unset ARRAY[INDEX]

declare -A ARRAY_NAME

ARRAY_NAME=([index_name1]="value1" [index_name2]="value2" ...)

bash腳本程式設計之bash的内置字元串處理工具:

字元串切片:(基于位置取字串)

${var:offset:number}:取字元串的子串;

${var: -length}:取字元串的最右側的幾個字元;

注意:冒号後必須有一個空格;

]# name=jerry

]# echo ${name:2}

顯示結果:rry

]# echo ${name:2:2}

顯示結果:rr

]# echo ${name: -4}

顯示結果:erry

基于模式取字串:

${var#*word}:

其中word是隻讀的分隔符;功能:從左向右,查找var變量所存儲的字元串中,第一次出現的word分隔符,删除字元串開頭至此分隔符之間的所有字元;

${var##*word}:(可用于取路徑基名、端口号)

其中word是隻讀的分隔符;功能:從左向右,查找var變量所存儲的字元串中,最後一次出現的word分隔符,删除字元串開頭至此分隔符之間的所有字元;

]# mypath="/etc/init.d/functions"

]# echo ${mypath#*/}:顯示内容:etc/init.d/functions;

]# echo ${mypath##*/}:顯示内容:functions;(即取路徑基名)

${var%word*}:(可用于取路徑名)

其中word是隻讀的分隔符;功能:從右向左,查找var變量所存儲的字元串中,第一次出現的word分隔符,删除此分隔符至字元串尾部之間的所有字元;

${var%word*}:

其中word是隻讀的分隔符;功能:從右向左,查找var變量所存儲的字元串中,最後一次出現的word分隔符,删除此分隔符至字元串尾部之間的所有字元;

]# echo ${mypath%/*}:顯示内容:/etc/init.d;(即取路徑名)

]# echo ${mypath%%/*}:顯示内容:為空;

]# mypath="etc/init.d/functions"

]# echo ${mypath%%/*}:顯示内容:etc;

]# url="http://www.magedu.com:80"

]# echo ${url##*:}:顯示内容:80;(取端口号)

]# echo ${url%%:*}:顯示内容:http;

查找替換:

${var/PATTERN/SUBSTI}:

查找var所表示的字元串中,第一次被PATTERN所比對到的字元串,并将其替換為SUBSTI所表示的字元串;

${var//PATTERN/SUBSTI}:

查找var所表示的字元串中,所有被PATTERN所比對到的字元串,并将其全部替換為SUBSTI所表示的字元串;

行首/尾錨定:

${var/#PATTERN/SUBSTI}:

查找var所表示的字元串中,行首被PATTERN所比對到的字元串,并将其替換為SUBSTI所表示的字元串;

${var/%PATTERN/SUBSTI}:

查找var所表示的字元串中,行尾被PATTERN所比對到的字元串,并将其替換為SUBSTI所表示的字元串;

注意:PATTERN中使用glob風格的通配符;

]# userinfo="root:x:0:0:root admin:/root:/binb/chroot"

]# echo ${userinfo/root/ROOT}:顯示内容:ROOT:x:0:0:root admin:/root:/binb/chroot;替換第一次;

]# echo ${userinfo//r??t/ROOT}:顯示内容:ROOT:x:0:0:ROOT admin:/ROOT:/binb/chROOT;替換所有;

]# echo ${userinfo/#r??t/ROOT}:顯示内容:ROOT:x:0:0:root admin:/root:/binb/chroot;行首替換;

]# echo ${userinfo/%r??t/ROOT}:顯示内容:root:x:0:0:root admin:/root:/binb/chROOT;行尾替換;

查找删除:

${var/PATTERN}:查找var字元串中,隻删除第一次被PATTERN比對到的字元串;

${var//PATTERN}:查找var字元串中,删除所有被PATTERN所比對到的字元串;

${var/#PATTERN}:查找var所表示的字元串中,隻删除行首被PATTERN所比對到的字元串;

${var/%PATTERN}:查找var所表示的字元串中,隻删除行尾被PATTERN所比對到的字元串;

字元大小寫轉換:

${var^^}:把var中的所有小寫字元轉換成大寫字元;

${var,,}:把var中的所有大寫字元轉換成小寫字元;

]# echo ${url^^}:顯示内容:HTTP://WWW.MAGEDU.COM:80;轉為大寫:

]# myurl=${url^^}

]# echo ${myurl,,}:顯示内容:http://www.magedu.com:80;轉為小寫;

變量指派:

${var:-VALUE}:如果var變量為空,或未設定,則傳回VALUE,否則,傳回var變量值;

${var:=VALUE}:如果var變量為空,或未設定,則傳回VALUE并将VALUE指派給var變量,否則,傳回var變量值;

變量hi為空,沒有定義值;

]# echo ${hi:-world}:顯示内容:world;

]# hi="hello"

]# echo ${hi:-world}:顯示内容:hello;

]# echo ${hi:=world}:顯示内容:hello;

]# unset hi:撤銷hi變量的值;

]# echo ${hi:=world}:顯示内容:world;

]# echo $hi:此時hi變量被指派了;

${var:+VALUE}:如果var變量不空,則傳回VALUE;否則,也沒什麼意義;

${var:?ERRO_INFO}:如果var變量為空,或未設定,則傳回ERRO_INFO為錯誤提示;否則,傳回var的值;

練習:腳本完成如下功能;(一定完成,後續課程實驗要用到)

(1)提示使用者輸入一個可執行的指令的名稱;

(2)擷取此指令所依賴到的所有庫檔案清單;

(3)複制指令至某目錄(例如/mnt/sysroot,即把此目錄當做根)下的對應的路徑中;

bahs,/bin/bash ==> /mnt/sysroot/bin/bash

usradd,/usr/sbin/useradd ==> /mnt/sysroot/usr/sbin/usradd

(4)複制此指令依賴到的所有庫檔案至目錄目錄下的對應路徑下;

/lib64/ld-linux-x8664.so2 ==> /mnt/sysroot/lib64/ld-linux-x8664.so.2

進一步:

每次複制完成一個指令後,不要退出,而是提示使用者繼續輸入要複制的其它指令,并重複完成如上功能,直到使用者輸入“quit”退出腳本;

寫一個腳本:前面的練習解答

使用ping指令探測,172.16.1.1-172.16.67.1範圍内的所有主機是否線上,線上顯示為up,不線上顯示為down,分别統計主機數量;

練習:腳本實作,探測C類、B類、A類網絡中的所有主機是否線上;

cping() {

local i=1 

while [ $i -le 245 ];do

    if ping -W 1 -c 1 $1.$i &>/dev/null;then

            echo "$1.$i is up"

    else 

            echo "$1.$i is down"

    fi  

#cping 192.168.0

bping() {

local j=0 

while [ $j -le 255 ];do

    cping $1.$j

    let j++ 

#bping 172.16

aping() {

local x=0 

while [ $x -le 255 ];do

    bping $1.$x

    let x++ 

aping 10

擴充:可改造以上腳本,提示使用者輸入任何網絡位址或網絡位址,擷取其網絡,并掃描其網段;

都可ping這個位址,先判斷ip位址類别,然後調用相應的函數,如輸入的是10.0.0.1,把ip位址第一段切出來進行比較是否為A(1-127)、B(128-191)、C(192-223))類網,然後再各自範圍内調用相應的函數實作;

bash腳本程式設計之信号捕捉

trap指令:就在腳本第一行,張網捕捉信号即可;

trap 'COMMAND' SIGANLS

-l:列出信号;

常可以進行捕捉信号:HUP、INT

COMMAND:可以使用分号分隔多個指令,還可以是一個函數;

注意:trap指令不能捕捉信号為:15-SIGTERM(terminal)和9-SIGKILL(kill);

因為捕捉信号的主要目的在于可以定義一旦信号到達以後,作出什麼操作,可以不是預設操作;是以kill信号等不能随意被捕捉;

檢視信号清單:

]# trap -l

]# kill -l

檢視信号類型解釋:

]# man 7 signal

trap 'echo "quit"; exit 1' INT 

for i in {1..254};do

        ping 172.16.$i.1

示例:使用trp捕捉,函數實作

ping172.16.1-254.1把結果儲存在/tmp/目錄下建立的臨時目錄下,然後退出時,再删掉那些臨時檔案;

此腳本,不能删除最後一次沒有捕捉到的臨時檔案;

declare -a hosttmpfiles

trap 'mytrap' INT 

mytrap() {

    echo "quit"

    rm -f ${hosttmpfiles[@]}

    exit 1

for i in {1..50};do

    tmpfile=$(mktemp /tmp/ping.XXXXX)

    if ping -W 1 -c 1 172.16.$i.1 &>/dev/null;then

        echo "172.16.$i.1 is UP" | tee $tmpfile

    else

        echo "172.16.$i.1 is down" | tee $tmpfile

    fi  

        hosttmpfiles[${#hosttmpfiles[*]}]=$tmpfile

在bash中使用ACSII顔色:

格式:\033[前#景顔#色;背#景顔#色mSTRING\033[0m

  \033[#;#;#mSTRING\033[0m

多種控制符可組合使用,彼此間用分号隔開;

\033[31mhello\033[0m

\033[:表示控制鍵Ctrl;

\033[0m:表示控制結束;

31m:表示前景色;

左側數字:(可同時設定前景、背景色)

3:表示前景色;

4:表示背景色;

右側數字:表示顔色;

1:紅色;

2:綠色;

3:金色;

4:藍色;

5:紫色;

6:青色;

7:灰色;

例如:\033[3mhello\033[0m

#m:表示字型

1:粗體;

4:加下劃線;

5:閃爍;

7:前背景反色;

8:隐藏;

]# echo -e "\033[31mhello\033[0m":前景色為紅色;

]# echo -e "\033[41mhello\033[0m":背景色為紅色;

]# echo -e "\033[41;32mhello\033[0m":前景為綠色,背景為紅色;

]# echo -e "\033[7mhello\033[0m":前背景反色;

]# echo -e "\033[4mhello\033[0m":加下劃線;

]# echo -e "\033[42;35;5mhello\033[0m":背景綠色,前景紫色,閃爍;

内置環境變量:PS1

指令行提示符格式;

可自定義指令行提示符格式:

export PS1='[\033[31m\u\033[0m@\033[32m\h\033[0m \033[35m\W\033[0m]\$'

但是設定後,有副作用;

]# echo $PS1

顯示内容:[\u@\h \W]\$

dialog指令:(需要yum install安裝)

display dialog boxes from shell scripts

dialog common-options box-options

box-options:

有三個參數:text、height、width

--calendar:月曆框;

--dselect:選擇目錄框;

--editbox:編輯框;

--form:表單;

--gauge:進度條;

--infobox:資訊框;

--inputbox:輸入空;

--inputmenu:輸入菜單;

--menu:菜單;

--msgbox:消息框;

--passwordbox:密碼框,顯示為*号;

]# yum info dialog:檢視dialog指令是否有可用安裝包;

]# yum install dialog:安裝dialog程式包;

]# dialog --msgbox hell 17 30:輸出消息框高17,寬30;

dialog指令可實作視窗化程式設計;有些是調用C庫中的curses實作的;

研究:

dialog指令,各窗體控件的使用方式;

如何擷取使用者選擇或鍵入的内容?dialog指令預設輸出資訊被定向到錯誤輸出流;

a=$(dialog),結果應該會儲存在變量中,但無法指派給變量,需要在dialog指令應用選項--stdout;

本文轉自 crystaleone 51CTO部落格,原文連結:http://blog.51cto.com/linsj/1759915,如需轉載請自行聯系原作者