溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

bash腳本總結(jié)

發(fā)布時(shí)間:2020-08-02 12:04:17 來源:網(wǎng)絡(luò) 閱讀:4615 作者:crystaleone 欄目:大數(shù)據(jù)

bash及shell腳本編程基礎(chǔ)


bash特性之多命令執(zhí)行:使用分號(hào)分隔,命令之間無關(guān)系;

]# cmd

方式一:]# cmd1 `cmd2`:命令引用實(shí)現(xiàn)多命令;

方式二:]# cmd1|cmd2|cmd3|...:管道實(shí)現(xiàn)多命令;

方式三:]# cmd1;cmd2;cmd3;...:分號(hào)實(shí)現(xiàn)多命令;


邏輯組合:操作的是命令的運(yùn)行狀態(tài)結(jié)果即退出碼;

]# cmd1 && cmd2 && ...

]# cmd1 || cmd2 ||...

]# !cmd1


退出碼:

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

1-255:表示為failure,假,錯(cuò)誤;


邏輯運(yùn)算:主要操作的是命令的運(yùn)行狀態(tài)結(jié)果即退出碼;

可認(rèn)為有一種判斷的機(jī)制在里面;判斷取決于是與運(yùn)算還是或運(yùn)算還取決于第一個(gè)操作的結(jié)果;


運(yùn)算數(shù):true(1),false(0)

COMMAND運(yùn)行狀態(tài)結(jié)果:

0:TRUE,成功;

1-255:FALSE,錯(cuò)誤;


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

true && true = true

true && false = false

第一個(gè)操作數(shù)為true,其結(jié)果取決于第二個(gè)操作數(shù);

false && true = false

false && false = false

第一個(gè)操作數(shù)為false,其結(jié)果至此可判定為false;

例如:

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

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


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

true || true = true

true || false = true

第一個(gè)操作數(shù)為true,其結(jié)果至此可判定為ture;

false || true = true

false || false = false

第一個(gè)操作數(shù)為false,其結(jié)果取決于第二個(gè)操作數(shù);

例如:

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

]# id hive


非:取反

! true = false

! fase = true

例如:

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


優(yōu)先級(jí):非 (高)<--與 <--或(低)


運(yùn)行腳本:

(1)賦予執(zhí)行權(quán)限,并直接運(yùn)行此程序文件;

chmod +x /PATH/TO/SCRIPT_FILE

/PATH/TO/SCRIPT_FILE


也可直接把腳本文件放在PATH環(huán)境變量中;例如把腳本文件放在/bin目錄下;


(2)直接運(yùn)行解釋器,以腳本文件為參數(shù);

bash /PATH/TO/SCRIPT_FILE

-x:調(diào)試執(zhí)行;

-n:判斷語(yǔ)法錯(cuò)誤;


bash特性之變量:


引號(hào)有三種類型:'',"",``

引號(hào):字符串引用符號(hào);

''單引號(hào):強(qiáng)引用;其內(nèi)部的變量不會(huì)替換;

""雙引號(hào):弱引用;其內(nèi)部的變量會(huì)被替換;

``反引號(hào):命令引用符號(hào);


例如:

]# echo '$PATH'

顯示結(jié)果:$PATH

]# echo "$PATH"

顯示結(jié)果:/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

]# echo `ls /root`

顯示結(jié)果:anaconda-ks.cfg install.log install.log.syslog


變量引用:${NAME},要使用花括號(hào)


變量:是內(nèi)存空間,有名稱,名稱即為變量名,對(duì)應(yīng)的內(nèi)存空間中的數(shù)據(jù)即為變量的值;


變量賦值:NAME=VALUE

=:賦值符號(hào);

把VALUE存儲(chǔ)到NAME指向的內(nèi)存空間中;


編程語(yǔ)言:

強(qiáng)類型:嚴(yán)格區(qū)分變量(內(nèi)存空間)中的數(shù)據(jù)類型;

弱類型:不區(qū)分變量中存儲(chǔ)的數(shù)據(jù)類型,統(tǒng)一為字符型;

bash:統(tǒng)統(tǒng)默認(rèn)為字符型數(shù)據(jù),變量無需事先聲明;


變量為什么有類型?

存儲(chǔ)空間、存儲(chǔ)格式、參與的運(yùn)算、...



變量命名:只能使用字母、數(shù)字和下劃線;且不能以數(shù)字開頭;

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

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

變量替換:把變量引用符號(hào)出現(xiàn)的位置替換為其指向的內(nèi)存空間中的數(shù)據(jù);


bash的變量種類:

根據(jù)作用域劃分:作用域:生效范圍,可引用到的范圍;

變量目的:

(1)變量用于存數(shù)據(jù),可重復(fù)多次使用這個(gè)數(shù)據(jù);

(2)可多次修改變量里面的數(shù)據(jù),以達(dá)到演進(jìn)、迭代目的;


本地變量

環(huán)境變量

局部變量(函數(shù)中)


位置參數(shù)變量:

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

retval=$?

保存的是命令執(zhí)行的狀態(tài)結(jié)果;


exit結(jié)束shell進(jìn)程;


pstree命令:顯示進(jìn)程樹;

tree命令:顯示目錄樹;


本地變量:作用域?yàn)楫?dāng)前shell進(jìn)程;不包括其子進(jìn)程;

定義本地變量:

本地變量賦值:NAME=VALUE

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

""

查看變量:set

撤銷變量:unset NAME

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

所有的本地變量在shell進(jìn)程終止時(shí),會(huì)被自動(dòng)撤銷;

例如:

]# pstree:查看shell進(jìn)程樹;

]# name="obama":定義本地變量;僅當(dāng)前shell進(jìn)程有效;

]# echo $name

切換到另外的進(jìn)程查看name變量:

]# echo $name:內(nèi)容為空;本地變量在同級(jí)進(jìn)程或子進(jìn)程都無效;


]# set:查看本地變量;

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

]# animal="goat"

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

環(huán)境變量:作用域?yàn)楫?dāng)前shell進(jìn)程及其子進(jìn)程;但不包括同級(jí)進(jìn)程;

環(huán)境變量聲明和賦值:

declare -x NAME[=VALUE]

-r:定義為只讀變量;

export NAME[=VALUE]

可以把本地變量聲明環(huán)境變量;

環(huán)境變量引用方式:

${NAME},$NAME


注意:bash內(nèi)嵌了很多環(huán)境變量,名稱為全大寫字母;例如:HOME,UID,PWD,SHELL,PATH,HISTSIZE等等;

主要用于工作的特殊環(huán)境;


查看環(huán)境變量命令:

export,declare -x

env,printenv


撤銷環(huán)境變量:

unset NAME

例如:

]# declare -x animal:聲明環(huán)境變量;

]# /bin/bash:環(huán)境變量在當(dāng)前shell進(jìn)程及其子進(jìn)程有效;

]# echo ${animal}:花括號(hào)可省略;

]# export:查看環(huán)境變量;

]# declare -x:查看環(huán)境變量;

]# env:查看環(huán)境變量;顯示格式不同;

]# printenv:查看環(huán)境變量;顯示格式不同;

]# unset namimal:撤銷環(huán)境變量;

例如:

]# ls /etc

]# retval=$?:把環(huán)境變量的值存儲(chǔ)在變量中,方便使用;

]# lll /etc

]# echo $?:查看環(huán)境變量狀態(tài)返回值;

]# echo $retval:查看之前的環(huán)境變量狀態(tài)返回值,這就是變量的意義;


只讀變量:就是常量,無法修改,無法撤銷;生命周期同當(dāng)前shell;

定義只讀變量:不支持重新賦值,也不支持撤銷;

(1)declare -r NAME

(2)readonly NAME


例如:

]# username="Lu Youjiao"

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

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

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



bash腳本編程之算術(shù)運(yùn)算

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

shell變量是一種很弱的變量,默認(rèn)情況下,一個(gè)變量保存一個(gè)串,shell不關(guān)心這個(gè)串是什么含義,所以弱要進(jìn)行數(shù)學(xué)運(yùn)算,必須使用一些命令例如let,declare,expr,雙括號(hào)等;


算術(shù)運(yùn)算

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

shell變量是一種很弱的變量,默認(rèn)情況下,一個(gè)變量保存一個(gè)串,shell不關(guān)心這個(gè)串是什么含義,所以弱要進(jìn)行數(shù)學(xué)運(yùn)算,必須使用一些命令例如let,declare,expr,雙括號(hào)等;


算術(shù)運(yùn)算格式語(yǔ)法:

(1)let VAR=$num1 op $num2(算術(shù)運(yùn)算表達(dá)式)

(2)VAR=$[算術(shù)運(yùn)算表達(dá)式]

(3)VAR=$((算術(shù)運(yùn)算表達(dá)式))

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


注意:有些時(shí)候乘法符號(hào)需要轉(zhuǎn)義;


練習(xí):腳本完成,添加3個(gè)用戶,求三用戶的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"


增強(qiáng)型變量賦值:

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

自身等于自身+數(shù)值,使用let命令;


例如:

    ]# declare -i i=1    

    ]# i=$[$i+1]                           

    ]# echo $i

此時(shí)就可用增強(qiáng)型賦值:

    ]# let i+=1


變量做某種算術(shù)運(yùn)算后回存至此變量中;

    let i=$i+#

    let i+=#

    #:代表數(shù)字


自增:

    VAR=$[$VAR+1]

    let VAR+=1

    let VAR++

自減:

    VAR=$[$VAR-1]

    let VAR-=1

    let VAR--


練習(xí):

1、腳本實(shí)現(xiàn),計(jì)算/etc/passwd文件中第15個(gè)用戶和第18個(gè)用戶的ID號(hào)之和;

分解:做a,b2個(gè)id號(hào)的運(yùn)算,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、計(jì)算/etc/rc.d/init.d/functions和/ect/inittab文件中的空白行數(shù)之和;

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腳本編程之條件測(cè)試:

判斷某需求是否滿足,需要由測(cè)試機(jī)制來實(shí)現(xiàn);


如何編寫測(cè)試表達(dá)式以實(shí)現(xiàn)所需的測(cè)試:

例如:判斷某文件是否有空白行、判斷某用戶是否存在

(1)執(zhí)行命令,并利用命令狀態(tài)返回值來判斷;

0:成功

1-255:失敗

$?:存儲(chǔ)上一條命令執(zhí)行狀態(tài)返回值;


例如:

判斷用戶centos是否登錄系統(tǒng):

    who|grep "^centos\>"

    echo $?:顯示上一個(gè)命令狀態(tài)返回值;

取得命令狀態(tài)返回值,0表示登錄,1-255表示沒登錄;


(2)測(cè)試表達(dá)式

test EXPRESSION

[ EXPRESSION ]

` EXPRESSION `


字符比較時(shí),用雙中括號(hào)

注意:EXPRESSION兩端必須要有空白字符,否則語(yǔ)法錯(cuò)誤;


bash腳本編程之測(cè)試類型:

數(shù)值測(cè)試

字符串測(cè)試

文件測(cè)試


數(shù)值測(cè)試:數(shù)值之間的比較


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

-ne:是否不等于;

-gt:是否大于;

-ge:是否大于等于;

-lt:是否小于;

-le:是否小于等于;

例如:

]# test 2 -gt 3

]# [ $A -eq $B ]

練習(xí):

centos用戶id是否比ubuntu用戶的ID大?

a=$(id -u centos)

b=$(id -u ubunto)

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


字符串測(cè)試比較

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

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

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

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

=~:左側(cè)字符串是否能被右側(cè)的PATTERN所匹配(左邊是否包含右邊),包含為真;


例如:

]# name=uubuntuu

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

]# echo $?


練習(xí):

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

  ]# a=$(hostname)

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


字符串是否為空:  

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

空則為真,不空則為假

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

不空則為真,空則為假;

注意:

(1)字符串比較要加引號(hào),表示引用;即不做變量替換可用單引號(hào),做變量替換要用雙引號(hào);

(2)字符串比較時(shí),要使用` `雙中括號(hào);            


練習(xí):

主機(jī)名如果為空,或者為localhost.locadomain或者包含localhost或者包含linux則統(tǒng)統(tǒng)將其設(shè)為www.magedu.com

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

注意:使用-o邏輯時(shí),字符測(cè)試比較符不能有空格且字符要用引號(hào),不能用雙中括號(hào)。


文件測(cè)試:

存在性測(cè)試

-a FILE

-e FILE:文件的存在性測(cè)試,如果存在,則為真;

例如:

]# [ -e /etc/passwd ]


文件的存在性及文件類型測(cè)試:既能測(cè)試存在性又能測(cè)試類別

-b FILE:文件是否存在并且為塊設(shè)備文件;

-c FILE:文件是否存在并且為字符設(shè)備文件;

-d FILE:文件是否存在并且為目錄文件;

-f FILE:文件是否存在并且為普通文件;

-h FILE或-L FILE:文件是否存在并且為符號(hào)鏈接文件;

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

-S FILE:文件是否存在并且為套接字文件;

例如:

]# [ -c /dev/null ]


文件權(quán)限測(cè)試:

-r FILE:文件是否存在并且對(duì)當(dāng)前用戶可讀;

-w FILE:文件是否存在并且對(duì)當(dāng)前用戶可寫;

-x FILE:文件是否存在并且對(duì)當(dāng)前用戶可執(zhí)行;

例如:

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


特殊權(quán)限測(cè)試:

-u FILE:文件是否存在并且擁有SUID權(quán)限;

-g FILE:文件是否存在并且擁有SGID權(quán)限;

-k FILE:文件是否存在并且擁有sticky權(quán)限;

例如:

[ -u /usr/bin/passwd ]


文件是否有內(nèi)容:

-s FILE:是否有內(nèi)容,有則為真:

例如:

[ -s /etc/fstab ]


文件時(shí)間戳是否變化:

-N FILE:文件自從上一次讀操作之后,是否被改過;


文件從屬關(guān)系測(cè)試:

-O FILE:當(dāng)前用戶是否為文件的屬主;

-G FILE:當(dāng)前用戶是否為文件的屬組;


雙目測(cè)試:

FILE1 -ef FILE2:文件1與文件2是否指向同一個(gè)文件系統(tǒng)上相同inode的硬鏈接;

FILE1 -nt FILE2:文件1是否新于文件2;

FILE1 -ot FILE2:文件1是否舊于文件2;


組合測(cè)試條件:

邏輯運(yùn)算:

第一種方式:

COMMAND1 && COMMAND2:與運(yùn)算;

COMMAND1 || COMMAND2:或運(yùn)算;

! COMMAND(取反)


例如:

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


第二種方式:

expresssion1 -a expression2

expresssion1 -o expression2

! expresssion或-not expresssion


例如:

[ -O FILE -a -x FILE ]:當(dāng)前引用是否為file文件的屬主,且是否有執(zhí)行權(quán)限;


練習(xí):將當(dāng)前主機(jī)名稱保存至hostName變量中;

主機(jī)名如果為空,或者為localhost.localdomain,則將其設(shè)置為www.magedu.com;

hostName=$(hostname)

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



腳本的狀態(tài)返回值:

默認(rèn)是腳本中執(zhí)行的最后一條命令的狀態(tài)返回值;

自定義狀態(tài)退出狀態(tài)碼;

exit [n]:n為自己指定的狀態(tài)碼;

    注意:shell進(jìn)程遇到exit時(shí),即會(huì)終止,因此,整個(gè)腳本執(zhí)行即為結(jié)束;


所以,exit不能隨意添加使用,要使用條件測(cè)試判斷后,確定是否添加exit退出;

埋點(diǎn)調(diào)試;使用$?能判斷是在哪個(gè)位置退出的,定位問題常用;


練習(xí):

腳本實(shí)現(xiàn),一行命令實(shí)現(xiàn),magedu用戶是否存在,不存在,則添加,如果存在,以狀態(tài)碼為5的方式退出;

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

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


bash腳本編程之向腳本傳遞參數(shù)

位置參數(shù)變量

命令行:*.sh argu參數(shù)1 argu參數(shù)2 argu參數(shù)3...

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


myscript.sh agru1 argu2...

引用方式:

    $1:保存argu參數(shù)1;

    $2:保存argu參數(shù)2;

    ...

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


輪替:

    shift [n]:位置參數(shù)輪替,n為數(shù)字默認(rèn)為1;表示為一次輪替前幾個(gè)參數(shù);

$1,$2...就叫位置參數(shù)變量,每次運(yùn)行腳本時(shí),通過傳遞參數(shù)變化來改變這些參數(shù)變量的值;


例如:

my_shell.sh ubuntu centos linux

引用方式:

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

useradd $1

useradd $2

useradd $3

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


shift #:表示刪掉指定參數(shù);把后面的參數(shù)往前補(bǔ)充;


練習(xí):

腳本實(shí)現(xiàn),通過命令傳遞兩個(gè)文本路徑給腳本,計(jì)算其空白行數(shù)(^$)之和;

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

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

sum=$[$a+$b]

echo "a is :$a"

echo "b is $b"

echo "sum is :$sum"


shift #:會(huì)自動(dòng)踢出命令參數(shù);


特殊變量:

$0:保存腳本文件路徑本身;

$#:保存腳本參數(shù)的個(gè)數(shù);

$*:保存所有參數(shù);把每個(gè)參數(shù)當(dāng)做一個(gè)個(gè)獨(dú)立參數(shù)顯示;

$@:保存所有參數(shù);把每個(gè)參數(shù)合在一起,當(dāng)做一個(gè)字符串參數(shù)顯示;


$0:表示命令行給定腳本文件路徑;


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

腳本內(nèi)容:echo $0

顯示結(jié)果為:/tmp/parameter_blanksum.sh

如果命令行是:bash parameter_blanksum.sh

腳本內(nèi)容不變,顯示結(jié)果為:parameter_blanksum.sh


$#:表示腳本參數(shù)的個(gè)數(shù);


例如:

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

腳本內(nèi)容:echo $#

顯示結(jié)果為:2


$*:表示參數(shù)為多個(gè)字符串;

$@:表示參數(shù)為一個(gè)字符串;


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

腳本內(nèi)容:echo $*

     echo $@

顯示結(jié)果為:/etc/init.d/functions /etc/init.d/network

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

但是$*表示為2個(gè)分開的路徑,而$@表示為一整行為一個(gè)字符串。


練習(xí):

1、判斷/etc/passwd是否為文件,如果為文件,則輸出/etc/passwd is files,該路徑通過命令傳遞的方式傳入,當(dāng)傳入的命令個(gè)數(shù)大于1,則報(bào)錯(cuò);

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

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

2、在root目錄下,寫腳本,可以一次性添加3名用戶,通過傳遞參數(shù)的方式,進(jìn)行用戶添加,當(dāng)傳遞的參數(shù)不符合3個(gè)的時(shí)候,報(bào)錯(cuò);

當(dāng)三名用戶添加完成后,需要將腳本進(jìn)行權(quán)限加固(鎖機(jī)制,不能再執(zhí)行),將腳本權(quán)限改成屬主可讀可寫可執(zhí)行;


! [ $# -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"


chmod 700 $0

echo "this script mode is 700"


過程式編程語(yǔ)言的代碼執(zhí)行順序:

順序執(zhí)行:逐條運(yùn)行;

選擇執(zhí)行:

代碼存在一個(gè)分支:條件滿足時(shí)才會(huì)執(zhí)行;

兩個(gè)或以上的分支:只會(huì)執(zhí)行其中一個(gè)滿足條件的分支;

循環(huán)執(zhí)行:

某代碼片段(循環(huán)體)要執(zhí)行0、1或多個(gè)來回(循環(huán));


順序執(zhí)行

條件選擇:

(1)&&,||

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

(3)case語(yǔ)句

循環(huán)執(zhí)行:for,while,until


bash腳本編程之if語(yǔ)句選擇分支

條件判斷:

shell執(zhí)行是順序執(zhí)行的


選擇分支

單分支的if語(yǔ)句

    if 測(cè)試條件;then(如果條件為真,則執(zhí)行下面語(yǔ)句)

        代碼分支

    fi

    if 測(cè)試條件

    then

        代碼分支

    fi


雙分支的if語(yǔ)句

if 測(cè)試條件;then

條件為真時(shí)執(zhí)行的分支

else

條件為假時(shí)執(zhí)行的分支

fi


多分支的if語(yǔ)句

if 測(cè)試條件;then

條件為真時(shí)候執(zhí)行的分支

elif 測(cè)試條件;then

elif 測(cè)試條件;then

elif 測(cè)試條件;then

else

條件為假時(shí)候執(zhí)行的分支

fi


例如:

通過參數(shù)傳遞給一個(gè)用戶名給腳本,此用戶如果不存在則創(chuàng)建用戶;


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

useradd $1

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

echo "add a user $1 finished"

else

echo "$1 is exist"

fi


示例:通過參數(shù)傳遞一個(gè)用戶名給腳本,此用戶不存在時(shí),則添加;(判斷表達(dá)方法:一種是命令,另一種是表達(dá)式放在中括號(hào)中或用test表示,判斷用戶是否存在用id或grep)

~]# vim useradd.sh

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

    useradd $1

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

    echo "add user $1 finished"

fi

~]# ./useradd.sh hbase

執(zhí)行結(jié)果為:add user hbase finished


加入了判斷參數(shù)是否存在的判斷if語(yǔ)句:

~]# vim useradd.sh

if [ $# -lt 1 ];then

    echo "at least one username"

    exit 2

fi


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

    useradd $1

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

    echo "add user $1 finished"

fi

~]# ./useradd.sh hbase


變?yōu)殡p分支判斷if語(yǔ)句:

~]# vim useradd.sh

if [ $# -lt 1 ];then

    echo "at least one username"

    exit 2

fi


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

    echo "user $1 exists"

else

    useradd $1

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

    echo "add user $1 finished"

fi

~]# ./useradd.sh hbase


練習(xí):

1、通過命令參數(shù),給定兩個(gè)數(shù)字,輸出其中較大的數(shù)值;

if [ $1 -gt $2 ] ;then

echo $1 is bigger

else

echo $2 is bigger

fi

或:

if [ ! $# -eq 2 ];then

 echo "give two number"

 exit 2;

fi


if [ $1 -gt $2 ];then

 echo "the bigg is $1"

elif [ $1 -lt $2 ];then

 echo "the bigg is $2"

else

 echo "$1=$2"

fi


2、通過命令參數(shù),給定兩個(gè)文本文件名,如果某文件不存在,則結(jié)束腳本,如果都存在返回每個(gè)文件的行數(shù),并echo其中行數(shù)較多的文件名;

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

fi


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"

else

 echo "$f2 is more"

fi

或:

if ! [ $# -eq 2 ];then

 echo "give 2 files"

 exit 20;

elif ! [ -e $1 ];then

 echo "$1 is not exist"

elif ! [ -e $2 ];then

 echo " $2 is not exist"

 exit 30;

else

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

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

echo "f1=$f1"

echo "f2=$f2"

fi


if [ $f1 -gt $f2 ];then

 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"

else

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


fi


3、通過命令行參數(shù)給定一個(gè)用戶名,判斷ID號(hào)是偶數(shù)還是奇數(shù);


多分支if語(yǔ)句


選擇執(zhí)行:

(1)&&,||

(2)if語(yǔ)句

(3)case語(yǔ)句


if語(yǔ)句:三種格式

單分支的if語(yǔ)句

if CONDITION;then

if-ture-分支

fi


雙分支的if語(yǔ)句

if CONDITION;then

if-true-分支

else

if-false-分支

fi


多分支的if語(yǔ)句

if CONDITION1;then

條件1為真分支

elif CONDITION2;then

條件2為真分支

elif CONDITION3;then

條件3為真分支

...

elif CONDITIONn;then

條件nweizhen分支

else

所有條件均不滿足時(shí)的分支

fi


注意:即便多個(gè)條件可能同時(shí)滿足,分支只會(huì)執(zhí)行其中一個(gè),首先測(cè)試為真的條件分支執(zhí)行后,就退出;


示例:通過腳本參數(shù),傳遞文件路徑給腳本,判斷此文件的類型;

if [ $# -lt 1 ];then

echo "at lease one path"

exit 1

fi


if ! [ -e $1 ];then

echo "no such file"

eixt 2

fi


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語(yǔ)句其實(shí)就是簡(jiǎn)化版的多分支if語(yǔ)句,但未所有if語(yǔ)句都能轉(zhuǎn)化為case語(yǔ)句;


注意:if語(yǔ)句可以嵌套使用;


練習(xí):

1、寫腳本實(shí)現(xiàn)如下功能:

(1)傳遞參數(shù)給腳本,此參數(shù)為用戶名;

(2)根據(jù)其id來判斷用戶類型;

0:管理員

1-999:系統(tǒng)用戶

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"

else

echo "system user"

fi



2、寫腳本實(shí)現(xiàn)如下功能:

(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)提示用戶給出自己的選擇,然后顯示對(duì)應(yīng)其選擇的相應(yīng)系統(tǒng)信息;


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

else

echo "your choice fault option"

fi


bash腳本編程之for循環(huán)

循環(huán)執(zhí)行:將一段代碼重復(fù)執(zhí)行0、1或多次;

進(jìn)入循環(huán)條件:只有條件滿足時(shí)才進(jìn)入循環(huán);

退出循環(huán)條件:每個(gè)循環(huán)都應(yīng)該有退出條件,有機(jī)會(huì)退出循環(huán);


bash腳本有三種循環(huán)方式:

for循環(huán)

while循環(huán)

until循環(huán)


for循環(huán)有2種格式:

(1)遍歷列表

(2)控制變量


變量賦值有三種方式:

(1)VAR=VALUE,直接賦值;

(2)通過read,實(shí)現(xiàn)變量賦值;

(3)for循環(huán)中,用列表賦值給變量;

遍歷列表:

for VARAIBLE in LIST;do

循環(huán)體

done


進(jìn)入條件:只有列表有元素,即可進(jìn)入循環(huán);

退出條件:列表中的元素遍歷完成;


LIST的生成方式:

(1)直接給出;

(2)整數(shù)列表;

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

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

seq start end:從開始數(shù)字列出到結(jié)束數(shù)字;

seq start step end:從開始數(shù)字,根據(jù)步長(zhǎng),列出結(jié)束數(shù)字;

seq命令:顯示一系列數(shù)字

seq [start [increment]] last


(3)能返回一個(gè)列表的命令;

例如:ls命令

(4)glob通配符機(jī)制;

例如:/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


例如:循環(huán)添加三個(gè)用戶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"

fi

done


例如:在tmp目錄下創(chuàng)建10個(gè)文件f1-10;

for filename in {1..10};do

 touch /tmp/f$filename

done

注意:在如何時(shí)候,要考慮判斷條件;如上例,應(yīng)該先判斷文件是否存在;


例如:求100內(nèi)所有正整數(shù)之和;

declare -i sum=0

for i in {1..100};do

sum=$[$sum+$i]

done

echo $sum


例如:計(jì)算100內(nèi)的奇數(shù)和;

declare -i sum=0

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

 sum=$[$sum+$i]

done

echo $sum


例如:計(jì)算100內(nèi)的偶數(shù)和;

declare -i sum=0

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

 sum=$[$sum+$i]

done

echo $sum


示例:判斷/var/log目錄下的每個(gè)文件的類型;

file /var/log/*即可判斷,但要求用循環(huán)實(shí)現(xiàn);

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


done

練習(xí):

1、分別求100內(nèi)偶數(shù)之和,奇數(shù)之和;

計(jì)算100內(nèi)的奇數(shù)和;

declare -i sum=0

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

  sum=$[$sum+$i]

 done

 echo $sum


計(jì)算100內(nèi)的偶數(shù)和;

declare -i sum=0

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

  sum=$[$sum+$i]

 done

 echo $sum


2、計(jì)算當(dāng)前系統(tǒng)上所有用戶的id之和;

declare -i sum=0

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

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

sum=$[$sum+$i]

done

echo $sum



3、通過腳本參數(shù)傳遞一個(gè)目錄給腳本,然后計(jì)算此目錄下所有文本文件的行數(shù)之和;并說明此類文件的總數(shù);

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

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


declare -i filesum=0

declare -i sum=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  

done


for循環(huán)格式:

for VARAIBLE in LIST;do

循環(huán)體

done


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


for循環(huán)的特殊用法:

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

循環(huán)體

done

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


控制變量初始化:僅在循環(huán)代碼開始運(yùn)行時(shí)執(zhí)行一次;

控制變量修正語(yǔ)句:會(huì)在每輪循環(huán)結(jié)束會(huì)先進(jìn)行控制變量修正運(yùn)算,而后再做條件判斷;


示例:求100內(nèi)整正數(shù)之和


declare -i sum=0


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

        let sum+=$i

done

echo "sum: $sum"


練習(xí):打印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

done


bash腳本編程之while循環(huán)和until循環(huán)


while循環(huán):

while CONDITION;do

循環(huán)體

循環(huán)擴(kuò)展變量修正表達(dá)式(條件修正表達(dá)式)

done


進(jìn)入條件:CONDITION參數(shù)為“真”;

退出條件:CONDITION參數(shù)為“假”;


until循環(huán):

until CONDITION;do

循環(huán)體

循環(huán)擴(kuò)展變量修正表達(dá)式(條件修正表達(dá)式)

done


進(jìn)入條件:CONDITION參數(shù)為“假”;

退出條件:CONDITION參數(shù)為“真”;

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



例如:求100內(nèi)正整數(shù)和;

比for優(yōu)勢(shì)在于,如果數(shù)值比較多,for的列表會(huì)占用內(nèi)存,while則使用的是變量,占用內(nèi)存空間很小;

for循環(huán):

for i in {1..100};do

sum=$[$sum+$i]

done

echo $sum


while循環(huán):

declare -i sum=0

declare -i i=1

while [ $i -le 10 ];do

   sum=$[$sum+$i]

   let i++ 

done

echo $sum


until循環(huán):

declare -i sum=0

declare -i i=1

until [ $i -gt 100 ];do

   let sum+=$i

   let i++ 

done

echo $sum


練習(xí):分別使用for、while、until各自實(shí)現(xiàn);

1、求100內(nèi)所有偶數(shù)之和、奇數(shù)之和;

2、創(chuàng)建10個(gè)用戶,分別為user101-user110;密碼同用戶名;

3、打印九九乘法表;

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


1x1=1

1x2=2,2x2=4

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

循環(huán)嵌套:

外循環(huán)控制乘數(shù),內(nèi)循環(huán)控制被乘數(shù);

for j in {1..9};do

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

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

done

echo

done


進(jìn)入條件:

for:列表元素非空;

while:條件測(cè)試結(jié)果為真;

until:條件測(cè)試結(jié)果為假;

退出條件:

for:列表元素遍歷完成;

while:條件測(cè)試結(jié)果為假;

until:條件測(cè)試結(jié)果為真;


循環(huán)控制語(yǔ)句:

continue:提前結(jié)束本輪循環(huán),而直接進(jìn)入下一輪循環(huán)判斷;

while CONDITION1; do

CMD1

...

if CONDITIONS2; then

continue

fi

CMDn

...

done


示例:求100內(nèi)偶數(shù)和;


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

done

echo "evensum : $evensum"


break:提前跳出循環(huán)

while CONDITION1; do

CMD1

...

if CONDITIONS2; then

break

fi

done


break #:在循環(huán)嵌套時(shí),指明跳出哪層循環(huán);


sleep命令:

delay for a specified amount of time


sleep #

#:為數(shù)字默認(rèn)單位是s秒鐘,可用m分鐘,h小時(shí),d天為單位;




創(chuàng)建死循環(huán):

while true;do

循環(huán)體

done


退出方式:

某個(gè)測(cè)試條件滿足時(shí),讓循環(huán)體執(zhí)行break命令;


until false;do

循環(huán)體

done


示例:求100內(nèi)奇數(shù)和


declare -i oddsum=0

declare -i i=1


while true; do

       let oddsum+=$i

       let i+=2

       if [ $i -gt 100 ];then

               break

       fi  

done


練習(xí):每隔3秒鐘到系統(tǒng)上獲取已經(jīng)登錄的用戶的用戶信息,其中,如果aaa用戶登錄系統(tǒng),則記錄于日志中,并退出;


while true;do

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

               break

       fi  

       sleep 3

done

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


或改寫為:

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

       sleep 3

done


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


while循環(huán)的特殊用法(遍歷文件的行):


while read VARIABLE;do

循環(huán)體;

done < /PATH/FROM/SOMEFILE


依次讀取/PATH/FROM/SOMEFILE文件中的每一行,且將其值賦值給VARIABLE變量;


示例:找出ID號(hào)為偶數(shù)的用戶,顯示器用戶名、ID及默認(rèn)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"

       fi  

done < /etc/passwd


bash腳本編程之用戶交互

腳本參數(shù)

用戶交互:通過鍵盤輸入數(shù)據(jù)

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

-p 'PROMPT':輸出提示符,設(shè)置提示信息;;

-t TIMEOUT:設(shè)定超時(shí)退出時(shí)間;

name:是在腳本里設(shè)定的變量;


bash -n /path/to/some_script

檢測(cè)腳本中的語(yǔ)法錯(cuò)誤


bash -x /path/to/some_script

調(diào)試執(zhí)行


例如:腳本實(shí)現(xiàn),使用read添加用戶,密碼同用戶名;

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


useradd $a

echo $a

echo $b

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


例如:腳本交互,輸入指定用戶名,創(chuàng)建用戶并設(shè)定密碼;

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"

else

    useradd $name

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

    echo "add user $name finished"

fi


練習(xí):

1、判斷給定是兩個(gè)數(shù)值,誰(shuí)大誰(shuí)小

給定數(shù)值的方法;命令參數(shù),命令交互


read -p "give two  number: " a b


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


if [ $a -gt $b ];then

 echo " $a is bigger"

else 

 echo "$b is bigger"

fi


2、提示用戶輸入一個(gè)字符串,如果輸入的是quit,則退出,否則顯示其輸入的字符串內(nèi)容;

read -p "give a string: " a


if ! [ $a == quit ];then


 echo "show string is $a"

else


 exit 1

fi


3、背景:公司新員工,要開通系統(tǒng)賬號(hào)和統(tǒng)計(jì)出新員工的信息(通過交互方式);

讓用戶指定一個(gè)用戶名和密碼,如果用戶名之前存在,先進(jìn)行刪除,之后則為用戶添加系統(tǒng)賬號(hào);

完成后,需要統(tǒng)計(jì)員工的手機(jī)號(hào),email,qq,年齡,收集后存儲(chǔ)到該用戶的家目錄中;

以上完成后,詢問該用戶是否需要給用戶單獨(dú)創(chuàng)建一個(gè)工作目錄為/data/username,默認(rèn)是需要,如果不需要,則輸入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

fi


bash腳本編程之條件選擇case語(yǔ)句

case語(yǔ)句:


if中的多分支in語(yǔ)句:

if CONDITION1;then

分支1(CONDITION1為真時(shí)執(zhí)行的語(yǔ)句)

elif CONDITION2;then

分支2(CONDITION2為真時(shí)執(zhí)行的語(yǔ)句)

...

else CONDITION;then

分支n

fi


示例:顯示菜單給用戶,

disk) show disk info

mem) show memory info

cpu) show cpu info

*) QUIT

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

  (2)正確的選擇給出相應(yīng)信息,否則,提示重新選擇正確的選項(xiàng);


cat << EOF

cpu) display cpu information

mem) display memory infomation

disk) display disks infomation

quit) quit

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

EOF


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]

else

        echo "quit"

        exit 0

fi

done  


注意:用一個(gè)變量與多個(gè)值比較時(shí),就可使用case語(yǔ)句替換成if多分支語(yǔ)句;


case語(yǔ)句的語(yǔ)法格式:


case $VARAIBLE in

PAT1)

分支1

;;

PAT2)

分支2

;;

...

*)

分支n

;;

esac


表示變量VARAIBLE與多個(gè)模式比較PAT1、PAT2、...,每個(gè)分支用雙分號(hào)結(jié)尾,多分支執(zhí)行特點(diǎn)是只要第一個(gè)滿足條件,就不執(zhí)行下面的語(yǔ)句,即使下面的條件也滿足也不執(zhí)行了;雙分號(hào)可單獨(dú)成行,也可在分支語(yǔ)句的最后;PAT只支持glob風(fēng)格的通配符;僅適用于一般都是變量與PAT做等值比較或模式匹配比較時(shí),可替代if多分支語(yǔ)句;


示例:上例用case實(shí)現(xiàn)


cat << EOF

cpu) display cpu information

mem) display memory infomation

disk) display disks infomation

quit) quit

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

EOF


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

done


case $option in

cpu) 

       lscpu;;

mem) 

       free -m;;

disk)

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

*)

       echo "quit"

       exit 0;; 

esac


case支持glog風(fēng)格的通配符:

*:任意長(zhǎng)度的任意字符;

?:任意單個(gè)字符;

[]:范圍內(nèi)任意單個(gè)字符;

a|b:a或b;


示例:腳本實(shí)現(xiàn)服務(wù)框架(服務(wù)腳本不能以.sh結(jié)尾)

$lockfile,/var/lock/subsys/SCRIPT_NAME

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

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

(3)start則創(chuàng)建lockfile,并顯示啟動(dòng);stop則輸出lockfile,并顯示停止;restart則先刪除此文件再創(chuàng)建文件,然后顯示重啟完成;status則如果lockfile操作則顯示running,否則顯示為stopped;


# 下面2語(yǔ)句為服務(wù)腳本格式

# 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"

       fi

       ;;

stop)

       if [ $lockfile ];then

               rm -f $lockfile

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

       else

               echo "$prog is not running"

       fi  

       ;;  

restart)

       if [ -f $lockfile ];then

               rm -f $lcokfile

               touch $lockfile

               echo "restart $prog finished"

       else

               touch -f $lockfile

               echo "start $prog finished"

       fi  

       ;;  

status)

       if [ -e $lockfile ];then

               echo "$prog is running"

       else

               echo "$prog is stopped"

       fi  

       ;;  

*)

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

       exit 1

esac


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

]# chkconfig --add exercise

]# chkconfig --list exercise

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


服務(wù)運(yùn)行以后都會(huì)在/var/lock/subsys/下,創(chuàng)建一個(gè)鎖文件,名稱同服務(wù)名稱;


bash腳本編程之函數(shù):function(功能)

在過程式編程里:實(shí)現(xiàn)代碼重用

模塊化編程

結(jié)構(gòu)化編程


把一段獨(dú)立功能的代碼當(dāng)做一個(gè)整體,并為之取一個(gè)名字;命名的代碼段,此即為函數(shù);


注意:定義函數(shù)的代碼段不會(huì)自動(dòng)執(zhí)行,在調(diào)用時(shí)才執(zhí)行;所謂調(diào)用函數(shù),在代碼中給定函數(shù)名即可;

函數(shù)名出現(xiàn)的任何位置,在代碼執(zhí)行時(shí),都會(huì)被自動(dòng)替換為函數(shù)代碼;


語(yǔ)法一:

function function_name {

...函數(shù)體

}


語(yǔ)法二:

function_name() {

...函數(shù)體

}


函數(shù)的生命周期:每次被調(diào)用時(shí)創(chuàng)建,返回時(shí)終止;函數(shù)也有狀態(tài)返回值,其狀態(tài)返回值默認(rèn)為函數(shù)體中運(yùn)行的最后一條命令的狀態(tài)結(jié)果;就像腳本中使用exit #表現(xiàn)為自定義退出狀態(tài)結(jié)果;而函數(shù)用return表示自定義狀態(tài)返回值;

return [0-255]

0:成功;

1-255:失敗;


示例:給定一(或二)個(gè)用戶名,取得用戶的ID號(hào)和默認(rèn)shell;

沒用函數(shù):

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

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

else

        echo "no such user"

fi


使用函數(shù):

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

userinfo


示例:改寫腳本服務(wù)框架(服務(wù)腳本不能以.sh結(jié)尾)


# chkconfig: - 50 50

# description: test service script

#

prog=$(basename $0)

lockfile=/var/lock/subsys/$prog


start() {

        if [ -f $lockfile ];then

                echo "$prog is running yet"

        else

                touch $lockfile

lockfile=/var/lock/subsys/$prog


start() {

        if [ -f $lockfile ];then

                echo "$prog is running yet"

        else

                touch $lockfile

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

        fi

}      

stop() {

        if [ $lockfile ];then

                rm -f $lockfile

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

        else

                echo "$prog is not running"

        fi

}         

restart() {

        if [ -f $lockfile ];then

                rm -f $lcokfile

                touch $lockfile

                echo "restart $prog finished"

        else

                touch -f $lockfile

                echo "start $prog finished"

        fi

}         

status() {

        if [ -e $lockfile ];then

                echo "$prog is running"

        else

                echo "$prog is stopped"

        fi

}

usage() {

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

        exit 1

}


case $1 in

start)

       start ;;

stop)

       stop;;

restart)

       stop

       start ;;

status)

       suatus;;

*)

       usage

       exit 1;;

esac


函數(shù)返回值:

函數(shù)的執(zhí)行結(jié)果返回值:

(1)使用echo或printf命令進(jìn)行輸出;

(2)函數(shù)體中調(diào)用的命令的執(zhí)行結(jié)果;

函數(shù)的退出狀態(tài)碼:

(1)默認(rèn)取決于函數(shù)體中執(zhí)行的最后一條命令的退出狀態(tài)碼;

(2)自定義:使用return #


命令都有兩種返回值,一種為執(zhí)行結(jié)果返回值,一種為執(zhí)行的狀態(tài)結(jié)果返回值稱為退出狀態(tài)碼;在腳本中實(shí)現(xiàn)命令替換,命令替換的地方就調(diào)用命令執(zhí)行的結(jié)果,函數(shù)也一樣,函數(shù)替換是調(diào)用函數(shù)出現(xiàn)的地方,就是函數(shù)代碼執(zhí)行的結(jié)果;printf命令:不能換行,但輸出可定義格式化輸出;在awk命令時(shí)再介紹;


函數(shù)可以接受參數(shù):

傳遞參數(shù)給函數(shù):

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

在調(diào)用函數(shù)時(shí),在函數(shù)名后面以空白符分隔給定參數(shù)列表即可,例如,testfunction arg1 agr2 agr3 ...


示例:添加10個(gè)用戶,使用函數(shù)實(shí)現(xiàn),用戶名作為參數(shù)傳遞給函數(shù);

]# bash -x exercise.sh aaa

addusers() {

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

               return 5

       else

               useradd $1

               retval=$?

               return $retval

       fi  

}


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"

       else

               echo "unkown error"

       fi  

done


練習(xí):

1、腳本函數(shù)實(shí)現(xiàn)ping主機(jī),來測(cè)試主機(jī)的在線狀態(tài);

主程序:實(shí)現(xiàn)測(cè)試172.16.1.1-172.16.67.1范圍內(nèi)個(gè)主機(jī)的在線狀態(tài);


分別使用for,while和until循環(huán)實(shí)現(xiàn);

普通方式:

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

        fi

done

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


改版2:函數(shù)+while循環(huán)方式:

declare -i uphosts=0

declare -i downhosts=0

declare -i i=1


hostping() {

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

            echo "$i is up"

            let uphosts+=1

        else    

            echo "$1 is down"

            let downhosts+=1

        fi  

}


while  [ $i -le 67 ];do

    hostping 172.16.$i.1

    let i++ 

done


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


改版3:使用return,在主程序中統(tǒng)計(jì)ping的主機(jī)數(shù)量;

declare -i uphosts=0

declare -i downhosts=0

declare -i i=1


hostping() {

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

            echo "$i is up"

            return 0

        else    

            echo "$1 is down"

             return 1

        fi  

}


while  [ $i -le 67 ];do

    hostping 172.16.$i.1

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

    let i++ 

done


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


2、腳本函數(shù)實(shí)現(xiàn),打印nn乘法表;


變量作用域:

局部變量:作用域是函數(shù)的生命周期;在函數(shù)結(jié)束時(shí)被自動(dòng)銷毀;

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

本地變量:作用域是運(yùn)行腳本的shell進(jìn)程生命周期;因此,其作用范圍就是當(dāng)前shell腳本程序文件;


例如:

name=tom

setname() {

name=jerry

echo "Function: $name"

}

setnaem

echo "Shell: $name"

此時(shí)函數(shù)的name和shell的name都是jerry,變量name為本地變量,可在函數(shù)中調(diào)用;

顯示結(jié)果為:

Function:jerry

Shell: jerry


如果在以上語(yǔ)句中改為:local name=jerry

顯示結(jié)果為:

Function:jerry

Shell: tom


bash腳本編程之函數(shù)遞歸:

函數(shù)直接或間接調(diào)用自身;


做階乘或斐波那契數(shù)列時(shí)會(huì)用到函數(shù)遞歸;

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

函數(shù)階乘 傳遞參數(shù)為n

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

例如:斐波那契數(shù)列

每一個(gè)數(shù)值都是前2個(gè)數(shù)的和;求第n階的數(shù)是多少就用函數(shù);

1 1 2 3 5 8 13 21 ...


例如:傳遞參數(shù)為一個(gè)數(shù)字,實(shí)現(xiàn)數(shù)字的階乘;


fact() {

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

               echo 1

       else

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

       fi  

}

fact $1


例如:傳遞參數(shù)為一個(gè)數(shù)字,實(shí)現(xiàn)斐波那契數(shù)列


fab() {

       if [ $1 -eq 1 ];then

               echo -n "1 "

       elif [ $1 -eq 2 ];then

               echo -n "1 "

       else

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

       fi  

}

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

fab $i

done

ech


bash腳本編程之?dāng)?shù)組


函數(shù)、case語(yǔ)句

case語(yǔ)句語(yǔ)法格式:

case $VARIABLE in

PAT1)

分支1

;;

PAT2)

分支2

;;

...

*)

分支n

;;

esac


PATTERN:為Glob通配符;


函數(shù):能完成結(jié)構(gòu)化編程,實(shí)現(xiàn)代碼重用;

function function_name{

函數(shù)體

}


function_name() {

函數(shù)體

}


函數(shù)定義后,被調(diào)用才能執(zhí)行;

函數(shù)調(diào)用:給定函數(shù)名即可調(diào)用,也可給函數(shù)傳遞參數(shù),使用位置參數(shù)$1,$2,...


局部變量:local VARIABLE

生命周期為調(diào)用函數(shù)時(shí),函數(shù)體內(nèi);

數(shù)組:

程序=指令+數(shù)據(jù)

bash腳本中指令:就是整個(gè)編程中的語(yǔ)法關(guān)鍵字,加上各種系統(tǒng)上的命令,加上定義的函數(shù);

數(shù)據(jù):存在變量、文件中、或數(shù)據(jù)組織結(jié)構(gòu)中;


變量:存儲(chǔ)單個(gè)元素的內(nèi)存空間;

數(shù)組:存儲(chǔ)多個(gè)元素的連續(xù)的內(nèi)存空間;

數(shù)組名:整個(gè)數(shù)組只有一個(gè)名字;數(shù)組在第一個(gè)內(nèi)存空間中存儲(chǔ)的數(shù)字就是數(shù)組名指向的位置;

數(shù)組索引:編號(hào)從0開始;引用數(shù)組種的數(shù)據(jù)方式:

數(shù)組名[索引]

${ARRAY_NAME[INDEX]}


注意:bash-4及之后的版本,支持自定義索引格式,而不僅是0,1,2,...數(shù)字格式;

自定義索引格式的屬組,稱為關(guān)聯(lián)數(shù)組;


聲明數(shù)組:

declare -a NAME:聲明索引數(shù)組;

declare -A NAME:聲明關(guān)聯(lián)數(shù)組;


查看聲明幫助:

]# help declare

數(shù)組中的數(shù)據(jù)就是存在內(nèi)存中的一段連續(xù)的內(nèi)存空間,分別存儲(chǔ)多個(gè)連續(xù)的數(shù)據(jù),每個(gè)數(shù)據(jù)都是獨(dú)立的被管理單元,只不過沒有獨(dú)立的名稱,要通過數(shù)組名稱來索引使用,數(shù)組名稱加上一個(gè)下標(biāo)可理解為數(shù)據(jù)在數(shù)組中的標(biāo)識(shí)符;


數(shù)組中元素的賦值方式:

(1)一次只賦值一個(gè)元素:

ARRAY_NAME[INDEX]=value


例如:

]# animals[0]=pig

]# animals[1]=cat

]# echo $animals

]# echo ${animals[1]}


(2)一次賦值全部元素:

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

會(huì)自動(dòng)賦值為0,1,2,3,...


例如:

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

]# echo ${weekdays[2]}


(3)只賦值特定元素;

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

為稀疏格式的數(shù)組;


注意:bash支持稀疏格式的數(shù)組;


例如:

]# 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;


關(guān)聯(lián)數(shù)組:

]# declare -A world:聲明關(guān)聯(lián)數(shù)組;

]# world[us]"America"

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

]# world[uk]"unite kingdom"

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


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

注意:引用時(shí),只給數(shù)組名,表示引用下標(biāo)為0的元素;


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

${ARRAY_NAME[@]}:同上;


數(shù)組的長(zhǎng)度(數(shù)組中元素的個(gè)數(shù)):

${#ARRAY_NAME[*]}

${#ARRAY_NAME[@]}


例如:

]# echo "${#Linux[*]}:顯示數(shù)組元素個(gè)數(shù)4個(gè);

]# echo "${#animals[@]}:顯示數(shù)組元素個(gè)數(shù)2個(gè);

]# echo "${#animals}:顯示數(shù)組第一個(gè)元素的字符個(gè)數(shù)為3個(gè);

]# echo "${animals[*]}:顯示數(shù)組中所有元素;可生成列表;


示例:生成10隨機(jī)數(shù),并找出其中最大值和最小值;


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]}

done


echo "Max: $max"


練習(xí):

1、生成10個(gè)隨機(jī)數(shù),由小到達(dá)排序;

2、定義數(shù)組,數(shù)組中的元素是/var/log目錄下所有以.log結(jié)尾的文件;統(tǒng)計(jì)其下標(biāo)為偶數(shù)的文件中的行數(shù)之和;


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)

       fi  

done


echo "lines: $lines"


引用數(shù)組中的所有元素:

${ARRAY_NAME[*]}

${ARRAY_NAME[@]}

也可只返回有限的幾個(gè)元素;


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

offset:元素偏移量;

number:取元素的個(gè)數(shù);省略number時(shí),表示取偏移量之后的所有元素;


例如:

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

]# echo ${files[*]}

顯示結(jié)果:

/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}:表示從上面的數(shù)組中跳過2個(gè),取3個(gè);

顯示結(jié)果:

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


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

顯示結(jié)果:

/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


向非稀疏格式的數(shù)組中追加元素:

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

${#ARRAY_NAME[*]}]:表示取出數(shù)組中的元素個(gè)數(shù);


刪除數(shù)組中的某元素:

unset ARRAY[INDEX]


關(guān)聯(lián)數(shù)組:

declare -A ARRAY_NAME

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


bash腳本編程之bash的內(nèi)置字符串處理工具:


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

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

${var: -length}:取字符串的最右側(cè)的幾個(gè)字符;

注意:冒號(hào)后必須有一個(gè)空格;


例如:

]# name=jerry

]# echo ${name:2}

顯示結(jié)果:rry


]# echo ${name:2:2}

顯示結(jié)果:rr


]# echo ${name: -4}

顯示結(jié)果:erry


基于模式取字串:

${var#*word}:

其中word是只讀的分隔符;功能:從左向右,查找var變量所存儲(chǔ)的字符串中,第一次出現(xiàn)的word分隔符,刪除字符串開頭至此分隔符之間的所有字符;

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

其中word是只讀的分隔符;功能:從左向右,查找var變量所存儲(chǔ)的字符串中,最后一次出現(xiàn)的word分隔符,刪除字符串開頭至此分隔符之間的所有字符;


例如:

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

]# echo ${mypath#*/}:顯示內(nèi)容:etc/init.d/functions;

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


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

其中word是只讀的分隔符;功能:從右向左,查找var變量所存儲(chǔ)的字符串中,第一次出現(xiàn)的word分隔符,刪除此分隔符至字符串尾部之間的所有字符;

${var%word*}:

其中word是只讀的分隔符;功能:從右向左,查找var變量所存儲(chǔ)的字符串中,最后一次出現(xiàn)的word分隔符,刪除此分隔符至字符串尾部之間的所有字符;


例如:

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

]# echo ${mypath%%/*}:顯示內(nèi)容:為空;


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

]# echo ${mypath%%/*}:顯示內(nèi)容:etc;


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

]# echo ${url##*:}:顯示內(nèi)容:80;(取端口號(hào))

]# echo ${url%%:*}:顯示內(nèi)容: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風(fēng)格的通配符;


例如:

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

]# echo ${userinfo/root/ROOT}:顯示內(nèi)容:ROOT:x:0:0:root admin:/root:/binb/chroot;替換第一次;

]# echo ${userinfo//r??t/ROOT}:顯示內(nèi)容:ROOT:x:0:0:ROOT admin:/ROOT:/binb/chROOT;替換所有;

]# echo ${userinfo/#r??t/ROOT}:顯示內(nèi)容:ROOT:x:0:0:root admin:/root:/binb/chroot;行首替換;

]# echo ${userinfo/%r??t/ROOT}:顯示內(nèi)容: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所匹配到的字符串;


字符大小寫轉(zhuǎn)換:

${var^^}:把var中的所有小寫字符轉(zhuǎn)換成大寫字符;

${var,,}:把var中的所有大寫字符轉(zhuǎn)換成小寫字符;


例如:

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

]# echo ${url^^}:顯示內(nèi)容:HTTP://WWW.MAGEDU.COM:80;轉(zhuǎn)為大寫:

]# myurl=${url^^}

]# echo ${myurl,,}:顯示內(nèi)容:http://www.magedu.com:80;轉(zhuǎn)為小寫;


變量賦值:

${var:-VALUE}:如果var變量為空,或未設(shè)置,則返回VALUE,否則,返回var變量值;

${var:=VALUE}:如果var變量為空,或未設(shè)置,則返回VALUE并將VALUE賦值給var變量,否則,返回var變量值;


例如:

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

]# echo ${hi:-world}:顯示內(nèi)容:world;

]# hi="hello"

]# echo ${hi:-world}:顯示內(nèi)容:hello;

]# echo ${hi:=world}:顯示內(nèi)容:hello;


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

]# echo ${hi:=world}:顯示內(nèi)容:world;

]# echo $hi:此時(shí)hi變量被賦值了;


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

${var:?ERRO_INFO}:如果var變量為空,或未設(shè)置,則返回ERRO_INFO為錯(cuò)誤提示;否則,返回var的值;


練習(xí):腳本完成如下功能;(一定完成,后續(xù)課程實(shí)驗(yàn)要用到)

(1)提示用戶輸入一個(gè)可執(zhí)行的命令的名稱;

(2)獲取此命令所依賴到的所有庫(kù)文件列表;

(3)復(fù)制命令至某目錄(例如/mnt/sysroot,即把此目錄當(dāng)做根)下的對(duì)應(yīng)的路徑中;

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

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

(4)復(fù)制此命令依賴到的所有庫(kù)文件至目錄目錄下的對(duì)應(yīng)路徑下;

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


進(jìn)一步:

每次復(fù)制完成一個(gè)命令后,不要退出,而是提示用戶繼續(xù)輸入要復(fù)制的其它命令,并重復(fù)完成如上功能,直到用戶輸入“quit”退出腳本;


寫一個(gè)腳本:前面的練習(xí)解答

使用ping命令探測(cè),172.16.1.1-172.16.67.1范圍內(nèi)的所有主機(jī)是否在線,在線顯示為up,不在線顯示為down,分別統(tǒng)計(jì)主機(jī)數(shù)量;


分別使用for,while和until循環(huán)實(shí)現(xiàn);

普通方式:

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

        fi

done

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


改版2:函數(shù)+while循環(huán)方式:

declare -i uphosts=0

declare -i downhosts=0

declare -i i=1


hostping() {

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

            echo "$i is up"

            let uphosts+=1

        else    

            echo "$1 is down"

            let downhosts+=1

        fi  

}


while  [ $i -le 67 ];do

    hostping 172.16.$i.1

    let i++ 

done


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


改版3:使用return,在主程序中統(tǒng)計(jì)ping的主機(jī)數(shù)量;

declare -i uphosts=0

declare -i downhosts=0

declare -i i=1


hostping() {

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

            echo "$i is up"

            return 0

        else    

            echo "$1 is down"

             return 1

        fi  

}


while  [ $i -le 67 ];do

    hostping 172.16.$i.1

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

    let i++ 

done


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


練習(xí):腳本實(shí)現(xiàn),探測(cè)C類、B類、A類網(wǎng)絡(luò)中的所有主機(jī)是否在線;


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  

    let i++ 

done

}

#cping 192.168.0


bping() {

local j=0 

while [ $j -le 255 ];do

    cping $1.$j

    let j++ 

done

}

#bping 172.16


aping() {

local x=0 

while [ $x -le 255 ];do

    bping $1.$x

    let x++ 

done

}

aping 10


擴(kuò)展:可改造以上腳本,提示用戶輸入任何網(wǎng)絡(luò)地址或網(wǎng)絡(luò)地址,獲取其網(wǎng)絡(luò),并掃描其網(wǎng)段;

都可ping這個(gè)地址,先判斷ip地址類別,然后調(diào)用相應(yīng)的函數(shù),如輸入的是10.0.0.1,把ip地址第一段切出來進(jìn)行比較是否為A(1-127)、B(128-191)、C(192-223))類網(wǎng),然后再各自范圍內(nèi)調(diào)用相應(yīng)的函數(shù)實(shí)現(xiàn);


bash腳本編程之信號(hào)捕捉


trap命令:就在腳本第一行,張網(wǎng)捕捉信號(hào)即可;


trap 'COMMAND' SIGANLS

-l:列出信號(hào);


??梢赃M(jìn)行捕捉信號(hào):HUP、INT


COMMAND:可以使用分號(hào)分隔多個(gè)命令,還可以是一個(gè)函數(shù);


注意:trap命令不能捕捉信號(hào)為:15-SIGTERM(terminal)和9-SIGKILL(kill);

因?yàn)椴蹲叫盘?hào)的主要目的在于可以定義一旦信號(hào)到達(dá)以后,作出什么操作,可以不是默認(rèn)操作;所以kill信號(hào)等不能隨意被捕捉;


查看信號(hào)列表:

]# trap -l

]# kill -l

查看信號(hào)類型解釋:

]# man 7 signal


例如:

trap 'echo "quit"; exit 1' INT 

for i in {1..254};do

       ping 172.16.$i.1

done


示例:使用trp捕捉,函數(shù)實(shí)現(xiàn)

ping172.16.1-254.1把結(jié)果保存在/tmp/目錄下創(chuàng)建的臨時(shí)目錄下,然后退出時(shí),再刪掉那些臨時(shí)文件;

此腳本,不能刪除最后一次沒有捕捉到的臨時(shí)文件;


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

done


在bash中使用ACSII顏色:


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

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


多種控制符可組合使用,彼此間用分號(hào)隔開;


\033[31mhello\033[0m


\033[:表示控制鍵Ctrl;

\033[0m:表示控制結(jié)束;

31m:表示前景色;

左側(cè)數(shù)字:(可同時(shí)設(shè)置前景、背景色)

3:表示前景色;

4:表示背景色;

右側(cè)數(shù)字:表示顏色;

1:紅色;

2:綠色;

3:金色;

4:藍(lán)色;

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":背景綠色,前景紫色,閃爍;


內(nèi)置環(huán)境變量:PS1

命令行提示符格式;


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

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

但是設(shè)置后,有副作用;



例如:

]# echo $PS1

顯示內(nèi)容:[\u@\h \W]\$


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

display dialog boxes from shell scripts


dialog common-options box-options


box-options:

有三個(gè)參數(shù):text、height、width

--calendar:日歷框;

--dselect:選擇目錄框;

--editbox:編輯框;

--form:表單;

--gauge:進(jìn)度條;

--infobox:信息框;

--inputbox:輸入空;

--inputmenu:輸入菜單;

--menu:菜單;

--msgbox:消息框;

--passwordbox:密碼框,顯示為*號(hào);


]# yum info dialog:查看dialog命令是否有可用安裝包;

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


例如:

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


dialog命令可實(shí)現(xiàn)窗口化編程;有些是調(diào)用C庫(kù)中的curses實(shí)現(xiàn)的;

研究:

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

如何獲取用戶選擇或鍵入的內(nèi)容?dialog命令默認(rèn)輸出信息被定向到錯(cuò)誤輸出流;


a=$(dialog),結(jié)果應(yīng)該會(huì)保存在變量中,但無法賦值給變量,需要在dialog命令應(yīng)用選項(xiàng)--stdout;




向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI