Linux系統shell腳本
shell腳本編程:
基礎編程:
程序:指令+數據
程序編程風格:
過程式:以指令為中心,數據服務于指令
對象式:以數據為中心,指令服務于數據
程序的執行方式:
計算機:運行二進制指令;
編程語言:
低級:匯編
高級:編譯、解釋
編譯:高級語言—–>編譯器——–>目標代碼 (Java、c#)
解釋:高級語言—–>解釋器——–>機器代碼 (shell、Perl、Python)
編程基本概念:
編程邏輯處理方式:
順序執行
循環執行
選擇執行
shell編程:過程式、解釋執行
編程語言的基本結構:
數據存儲:變量數組
表達式:a + b
語句:if
shell腳本基礎:
shell腳本是包含一些命令或聲明,并符合一定格式的文本文件;
格式要求:首行shabang機制
#!/bin/bash
#!/usr/bin/python
#!/usr/bin/perl
shell 腳本的用途:
自動化常用命令
執行系統管理和故障排除
創建簡單的應用程序
處理文本或文件
shell腳本的創建:
第一步:使用文本編輯器來創建文本文件;
第一行必須包括shell聲明:
#!/bin/bash
添加注釋行:
注釋行以#開頭
添加運行命令:
…………………….
第二步:運行腳本文件:
給予執行權限,在命令行上指定腳本的絕對路徑或相對路徑
直接運行解釋器,將腳本作為解釋器程序的參數
腳本調試:
檢測腳本中的語法錯誤:
bash -n /path/to/somescript
調試執行腳本:
bash -x /path/to/somescript
shell變量應用:
本地變量:生效范圍為當前shell進程,對當前shell的子shell及其它shell進程均無效;
環境變量:生效范圍為當前shell進程及其子shell進程;
局部變量:生效范圍為當前shell進程中某代碼片段(通常指函數);
變量命名法則:
1、不能使用程序中的保留字,例如:if、for等;
2、只能使用數字、字母、及下劃線,且不能以數字開頭;
3、見名知意;
4、統一命名規范;
本地變量基本格式:
變量名=變量值
例:
[root@centos7 ~]# day=sunday
[root@centos7 ~]# echo $day
sunday
[root@centos7 ~]#
注意:當變量名稱容易和緊跟其后的其他字符相混淆時,需要添加 “{ }”將其包圍起來進行區分,否則將無法確定正確的變量名。
例:
[root@centos7 ~]# day=sunday
[root@centos7 ~]# echo ${day}hayyp
sundayhayyp
[root@centos7 ~]#
為變量賦值的常用方法:
在等號“=”后面直接指定變量內容是為變量賦值的最基本的方法,除此之外我們還可以使用 “雙引號”、“單引號”、“反撇號”、“read命令”。
雙引號:
使用雙引號時,允許在雙引號的范圍內使用$符號來引用其他變量的值;
“ ”:弱引用,雙引號中可以引用其他變量的值;
用法:name=”root” 或 name=”$USER”
例:
[root@centos7 ~]# echo $day
sunday
[root@centos7 ~]# today="today is $day"
[root@centos7 ~]# echo $today
today is sunday
[root@centos7 ~]#
單引號:
使用單引號時,將不允許在單引號的范圍內引用其他變量的值;在單引號中“$”符或其他任何符號將作為普通字符看待。
‘ ’:強引用,單引號中變量引用不會被替換為變量值,都當做普通字符看待;
例:
[root@centos7 ~]# echo $day
sunday
[root@centos7 ~]# today='today is $day'
[root@centos7 ~]# echo $today
today is $day
[root@centos7 ~]#
反撇號:
使用反撇號時,允許將執行特定命令的輸出結果賦值給變量;
用法:name=`command` 或 name=$(command)
例:
server_ip=$(ifconfig | sed -n "2p" | grep -E -o '(([0-9]|[1-9][0-9]|1[0-9]{2}| 2[0-4][0-9]|25[0- 5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])' | head -1 )
或
login_time=`date +%F-%T`
host_name=`hostname`
read命令:
我們可以使用bash的內置命令read來給變量賦值,read命令可以從終端鍵盤讀取輸入,實現簡單的交互過程。read將從標準輸入讀入一行內容,并以空格為分隔符,將讀入的各字段分別賦值給列表中指定的變量,多余的內容賦值給最后一個變量。
為了使交互操作更加友好,提高易用性,我們可以結合“-p”選項來設置提示信息,用于告知用戶應該輸入的內容。
例:
[root@centos7 profile.d]# read -p "please input a number :" number
please input a number :123
[root@centos7 profile.d]# echo $number
123
[root@centos7 profile.d]#
顯示已定義的所有變量(環境變量和本地變量局部變量):set命令
刪除本地變量:unset 變量名 (可以指定一個或多個變量名做參數)
環境變量:
為了使用戶定義的本地變量在所有的子shell環境中能夠繼續使用,減少重復設置工作,可以使用export命令將指定的變量設置為“全局變量”。export命令可以同時使用多個變量名作為參數,變量名之間以空格分隔。
用法:1、 export 變量名=變量值
或
2、 變量名=變量值
export 變量名
或
3、declare -x 變量名=變量值
declare -r 變量名=變量值(只讀變量,不能修改和刪除)
例:
現在在子shell中也可以使用父shell定義的環境變量
[root@centos7 Desktop]# export day=sunday
[root@centos7 Desktop]# echo $day
sunday
[root@centos7 Desktop]# bash
[root@centos7 Desktop]# echo $day
sunday
[root@centos7 Desktop]#
顯示所有環境變量:
export
env
printenv
declare -x
刪除環境變量:
unset 變量名
只讀變量:
只讀變量:只能聲明,不能修改和刪除;
readonly 變量名=變量值
declare -r 變量名=變量值
例:
[root@centos7 Desktop]# readonly today="today is sunday"
[root@centos7 Desktop]# declare -r year=2016
位置變量:
位置變量:用于讓shell腳本在執行過程中可以調用命令行中給出的位置參數;
位置變量采用“$n”的格式,其中“n”是參數的位置序號從( 1-9 )
例:$1 、$2、$3 、$4 、$5 、$6 、$7 、$8 、$9 、
特殊變量:
特殊變量是由bash程序預先定義好的一些特殊變量,用戶只能使用這些特殊變量,不能創建新的特殊變量或直接為特殊變量賦值。
$0:表示命令本身;
$#:表示傳遞給腳本的參數個數;
$*:表示所有位置參數的內容,全部參數合為一個字符串;
$@:傳遞給腳本的所有參數,每個參數為獨立的字符串;
$?:表示命令執行后返回的狀態,命令退出狀態為0表示命令執行正確,任何非0值得表示命令執行錯誤,(錯誤值1-255之間的任意數值)
$$:表示當前進程的進程號;
$!:表示后臺運行的最后一個進程的進程號;
注:$#、$@只在被雙引號包起來的時候才會有差異;
數值變量運算:
運算符:
“+”:加法運算;
“–”:減法運算;
“*”:乘法運算,直接用expr運算時需要轉義“\*”;
“/”:除法運算;
“**”:乘方;
“%”:取模運算,又稱為取余運算,即計算數值相除后的余數;
算數運算格式:
let var=算術運算表達式
var=$[算術運算表達式]
var=$((算術運算表達式))
var=$(expr $ARG1 $OP $ARG2 )
declare -i var=算術運算表達式
echo ‘算術運算表達式’ |bc
例:
[root@centos7 ~]# let sum=$num1+$num2
[root@centos7 ~]# sum=$[$num1+$num2]
[root@centos7 ~]# sum=$(($num1+$num2))
[root@centos7 ~]# sum=$(expr $num1 \* $num2)
[root@centos7 ~]# sum=`expr $num1 \* $num2`
[root@centos7 ~]# declare -i var=$num1+$num2
bash有內建的隨機數生成器:$RANDOM (1-32767)
echo $[$RANDOM%50] :0-49之間的隨機數;
賦值:
增強型賦值:
+= -= *= /= %=
let varOPERvalue
let count +=3 意思是:let count=count+3
自增,自減
let var+=1意思是:let var=var+1
let var++ 意思是:let var=var
let ++var 意思是:let var=var+
let var-=1 意思是:let var=var-1
let var– 意思是:let var=var
邏輯運算:
運算數:
真(true、yes、on、1)
假(false、no、off、0)
與:
1 && 1 = 1
1 && 0 = 0
0 && 1 = 0
0 && 0 = 0
或:
1 || 1 = 1
1 || 0 = 1
0 || 1 = 1
0 || 0 = 0
非:
! 1 = 0
! 0 = 1
短路法則:
~]# command1 && command2
command1為“假”,則command2不會執行操作;
反之,command1為“真”,則command2必須執行;
~]# command1 || command2
command1為“真”,則command2不會再執行;
反之,command1為“假”,則command2必須執行;
聚集命令:
有兩種聚集命令的方法:
1)復合式:date;who | wc -l
2)子shell:(date; who | wc -l)在子shell中運行的;
退出狀態:
進程使用退出狀態來報告成功或失?。?/span>
$?:變量中保存了最近一次命令執行狀態值;
0:代表成功;
1-255:代表失敗;
條件測試:
判斷某需求是否滿足,需要由測試機制來實現;
專用的測試表達式需要由測試命令輔助完成測試過程;
使用test測試命令時,可以有以下兩種形式;
test 條件表達式
或
[ 條件表達式 ]
[[ 條件表達式 ]]
注意:條件表達式兩端必須有空白字符,否則為語法錯誤;
bash的測試類型
文件測試:
數值測試:
字符串測試:
邏輯測試:
文件測試:
-d:測試是否為目錄;
-e:測試目錄或文件是否存在;
-c:測試是否為字符設備文件;
-f:測試是否為文件;
-r:測試當前用戶是否有權限讀??;
-w:測試當前用戶是否有權限寫入;
-x:測試當前用戶是否可執行該文件;
-L:測試是否為符號鏈接(link)文件;
-p:測試是否為管道文件;
-S:測試是否為套接字文件;
-s:測試文件是否存在且非空;
-g:測試是否擁有sgid權限;
-u:測試是否擁有suid權限;
-k:測試是否擁有sticky權限;
-N:測試文件自上一次被讀取之后是否被修改過;
-O:測試當前有效用戶是否為文件屬主;
-G:測試當前有效用戶是否為文件屬組;
file1 -ef file2 :測試file1與file2是否指向同一個設備上的相同inode
file1 -nt file2 :測試file1是否新于file2;
file1 -ot file2 :測試file1是否舊于file2;
例:
[root@centos7 ~]# [ -f /etc/passwd ] && echo yes
yes
[root@centos7 ~]#
數值測試:
數值比較:
-eq:第1個數等于第二個數;
-ne:第1個數不等于第二個數;
-gt:第1個數大于第二個數;
-lt :第1個數小于第二個數;
-ge:第1個數大于或等于第二個數;
-le:第1個數小于或等于第二個數;
例:
[root@centos7 ~]# sum=`cat /etc/passwd | wc -l`
[root@centos7 ~]# echo $sum
43
[root@centos7 ~]# [ $sum -ge 10 ] && echo "yes"
yes
[root@centos7 ~]#
字符串測試:
==:是否等于;
>:是否大于;
<:是否小于;
!=:是否不等于;
=~:左側字符串是否能夠被右側的pattern所匹配;
-z “string”:判斷指定的字符串是否為空,空則真,不空則假;
-n “sting” :判斷指定的字符串是否不空,空則假,不空則真;
-a : 并且的意思;
注意:
(1)字符串要加雙引號;
(2)要使用[[ ]]進行測試;
例:
測試$LANG變量是否等于en.US:
[root@centos7 ~]# [[ $LANG == en.US ]] || echo $LANG
en_US.UTF-8
[root@centos7 ~]#
測試abc字符串是否不等于def字符串:
[root@centos7 ~]# [[ "abc" != "def" ]] && echo "yes" || echo "no"
yes
[root@centos7 ~]#
測試文件是否為空:
[root@centos7 ~]# [[ -z `cat file1` ]] && echo "yes"
yes
[root@centos7 ~]#
測試文件是否為不空:
[root@centos7 ~]# [[ -n `cat file1` ]] && echo "yes"
yes
[root@centos7 ~]#
判斷a是否小于b:
[root@centos7 ~]# [[ "a" < "b" ]] && echo "yes"
yes
[root@centos7 ~]#
判斷aa是否能夠被模式[ac]匹配:
[root@centos7 ~]# [[ “aa” =~ [ac] ]] && echo "yes" || echo "no"
yes
[root@centos7 ~]#
邏輯測試:
邏輯測試是指同時使用兩個或(多個)條件表達式之間的關系;
&&邏輯與:表示前后兩個表達式都成立時整個測試結果才為真;否則為假;
||邏輯或:表示前后兩個條件至少有一個成立時整個測試結果即為真,否則結果為假;
!邏輯否:表示當指定的條件表達式不成立時,整個測試結果的命令為真;
例:
測試/etc/profile文件是否有執行權限:
root@centos7 ~]# [ ! -x /etc/profile ] && ls -l /etc/profile || echo "have x mode"
-rw-r–r–. 1 root root 1750 jun 7 2013 /etc/profile
[root@centos7 ~]#
shell腳本編程語言:
過程式編程語言:
順序執行
選擇執行
循環執行
if語句的結構:
單分支的if語句:
if 條件測試命令
then
命令序列1
fi
雙分支if語句:
if 條件測試命令
then
命令序列1
else
命令序列2
fi
多分支的if語句:
if 條件測試命令1
then
命令序列1
elif 條件測試命令2
then
命令序列2
else
命令序列3
fi
case語句:
case語句適用于需要進行多重分支的應用情況;
case支持glob風格的通配符:
*:任意長度任意字符;
?:任意單個字符;
[ ]:指定范圍內的任意單個字符;
a|b:a或b語句;
case 變量引用 in
pat1)
命令序列1
;;
pat2)
命令序列2
;;
pat3)
命令序列3
;;
*)
默認執行的命令序列
esac
注意:case行尾必須為單詞“in”,每一模式必須以右括號“)”結束;
雙分號“;;”表示命令序列的結束;
循環:
循環執行:
將某段代碼重復運行多次;
循環次數事先已知;
循環次數事先位置;
循環時執行進入條件和退出條件;
循環語句:
for while until
for循環:
for 變量名 in 列表;do
循環體
done
依次將列表中的元素賦值給“變量名”;每次賦值后即執行依次循環體;直到列表中的元素耗盡,循環結束。
示例:
for循環 99乘法表
1 #!/bin/bash
2 #multiplicationtables
3
4 for i in {1..9}
5 do
6 for j in {1..9}
7 do
8 if [ $i -ge $j ];then
9 let sum=$j*$i
10 echo -n -e "$j*$i=$sum\t"
11 fi
12 done
13 echo
14 done
17 unset i
18 unset j
19 unset sum
或
1 #!/bin/bash
2 #zheng
3
4 for ((i=1;i<=9;i++));do
5
6 for ((j=1;j<=i;j++));do
7
8 echo -e -n "${j}x${i}=$[${i}*${j}]\t"
9 done
10 echo
11 done
12 unset i
13 unset j
while 循環:
while 條件測試判斷 ;do
循環體
done
條件測試判斷:循環控制條件;進入循環之前,先做一次判斷,每一次循環之后會在次做判斷;條件為“true”,則執行依次循環,直到條件測試狀態為false終止循環;
因此:條件測試判斷一般應該有循環控制變量;而此變量的值會在循環體不斷的被修正;
進入條件:條件測試判斷為true;
退出條件:條件測試判斷為false;
示例:
測試192.168.3網段的在線主機狀態,并統計在線主機和離線主機的個數;
1 #!/bin/bash
2 #grep ServerIp
3
4 ip=192.168.3.
5 net=1
6 i=0
7 j=0
8
9 while [ $net -lt 255 ];do
10 ping -c1 -w1 ${ip}$net &> /dev/null
11 if [ $? -eq 0 ];then
12 echo "此${ip}$net地址正常"
13 let i++
14 else
15 echo "此${ip}$net地址不正常"
16 let j++
17 fi
18
19 let net++
20 done
21echo "活躍用戶:$i"
22 echo "不活躍用戶:$j"
while循環打印國際圍棋:
示例:
1 #!/bin/bash
2 #while打印國際圍棋
3 i=1
4
5 while [ $i -le 8 ];do
6
7 j=1
8 while [ $j -le 8 ];do
9 let sum=$i+$j
10 let m=$sum%2
11 # [ $m -eq 0 ] &&echo -en "\033[41;1m \033[0m" || echo -en "\033[43;1m \033[0m"
12 if [ $m -eq 0 ];then
13 echo -en "\033[41;1m \033[0m"
14 else
15 echo -en "\033[43;1m \033[0m"
16 fi
17 let j++
18
19 done
20 echo
21 let i++
22
23 done
24 unset i
25 unset j
26 unset sum
until循環:
until 條件測試判斷;do
循環體
done
進入條件:條件測試判斷為false
退出條件:條件測試判斷為true
示例:
猜數字游戲:
1 #!/bin/bash
2 #
3
4 echo "============================="
5 suiji=$(($RANDOM%10+1))
6 max=10
7 zuixiao=1
8
9 read -p "please input a number:" num
10
11 until [ $num -eq $suiji ];do
12
13 echo "你要猜$zuixiao 和 $max之間的數"
14
15 if [ $suiji -gt $num ];then
16
17 echo "你猜的太小了"
18 else
19 echo "你猜的太大了"
20 fi
21 read -p "please input a number:" num
22
23
24 done
25 echo "恭喜你猜對了"
26 unset suiji
27 unset max
28 unset zuixiao
continue命令:
continue即“繼續”的意思,用于暫停本次循環,跳轉至循環語句的頂部重新測試條件。
示例:
計算100以內所有偶數的和:
1 #!/bin/bash
2 #zheng
3
4
5 declare -i addsum=0
6 declare -i i=0
7
8 while [ $i -le 100 ];do
9 let i++
10 if [ $(($i%2)) -eq 1 ];then
11 continue
12
13 fi
14 let addsum+=$i
15
16 done
17
18
19 echo "oushu100 sum :$addsum "
20 unset addsum
21 unset i
break命令:
break即“終斷”的意思,用于跳出當前所在的循環體,但是并不退出程序;
示例:
求100以內偶數的和:(使用while、break命令)
1 #!/bin/bash
2 #zheng
3
4 declare -i i=0
5 declare -i sum=0
6
7 while true ;do
8 ((i+=2))
9 if [ $i -gt 100 ];then
10
11 break
12 fi
13 ((sum+=$i))
14 done
15 echo " $sum"
16 unset i
17 unset sumg
示例:
求100以內偶數的和:(使用until、break命令)
1 #!/bin/bash
2 #zheng
3
4 declare -i i=0
5 declare -i sum=0
6
7 until false ;do
8 ((i+=2))
9 if [ $i -gt 100 ];then
10 break
11 fi
12 ((sum+=$i))
13 done
14 echo " $sum"
15 unset i
16 unset sum
示例:
求100以內jishu之和:(使用while、break命令:)
1 #!/bin/bash
2 #zheng
3
4 declare -i i=1
5 declare -i sum=0
6
7 while true ;do
8 if [ $i -gt 100 ];then
9 break
10 fi
11 ((sum+=$i))
12 ((i+=2))
13 done
14 echo " $sum"
15 unset i
16 unset sum
sleep 命令:
示例:
檢測zheng用戶是否登錄系統:
1 #!/bin/bash
2 #zheng
3 #
4 while true;do
5
6 if who | grep "^zheng\>" &> /dev/null;then
7 break
8 fi
9 sleep 5
10 done
11
12 echo "zheng logged on " >> /var/log/messages
創建無線循環:
while true;do
循環體命令
done
until false;do
循環體命令
done
特殊用法:
while read line;do
循環體
done < /PATH/FROM/SOMEFILE
依次讀取/PATH/FROM/SOMEFILE文件中的每一行,且將每行賦值給變量line;
示例:
掃描/etc/passwd/文件每一行,如發現描述字段為空,則填充用戶名和單位電話為123456;
1 #!/bin/bash
2 #zheng
3
4 while read line;do
5 kong=$( echo $line| cut -d: -f5 )
6 if [ -z "$kong" ];then
7
8 user=$(echo $line | cut -d: -f1)
9 usermod -c "${user} 123456" $user &> /dev/null
10 echo "add user:$user"
11 fi
12
13 done </etc/passwd
14 unset kong
15 unset user
特殊用法:
for循環特殊用法:語法格式
for (( exp1; exp2; exp3 )); do COMMANDS; done
for循環的特殊格式:
for ((控制變量初始化;條件判斷表達式;控制變量的修正表達式));do
循環體命令
done
控制變量初始化:僅在運行到循環代碼段時執行依次;
控制變量的修正表達式:每輪循環結束會先進行控制變量修正運算,而后在做條件判斷;
示例:
1 #!/bin/bash
2 #zheng
3
4 for (( i=0;i<=100;i++ ));do
5
6 let sum+=$i
7
8 done
9
10 echo "$sum"
11
12 unset sum
select 循環與菜單:
select 變量名 in list;do
循環體命令
done
select 循環主要用于創建菜單,按數字順序排列的菜單項將顯示在標準錯誤上,并顯示PS3提示符,等待用戶輸入;
用戶輸入菜單中的某個數字,執行相應的命令
用戶輸入被保存在內置變量REPLY中;
select 與case
select 是個無限循環體,因此要記住使用break命令退出循環,或使用exit命令終止腳本。也可以按ctrl+c退出循環。
select 經常和case聯合使用
與for循環類似??梢允÷?in list。此時使用位置參量;
~ 示例:
1 #!/bin/bash
2 #zheng
3 #菜單
4 PS3="你好,想吃點什么,請點序號:"
5 select menu in 涼菜 熱菜 土豆 梅菜扣肉 雞蛋面;do
6 echo -n "你點的菜是: "
7
8 case $menu in
9
10 涼菜)
11 echo -e "\033[31m涼菜\033[0m"
12 ;;
13 熱菜)
14 echo -e "\033[31m熱菜\033[0m"
15 ;;
16 土豆)
17 echo -e "\033[31m土豆\033[0m"
18 ;;
19 梅菜扣肉)
20 echo -e "\033[31m梅菜扣肉\033[0m"
21 ;;
22 雞蛋面)
23 echo -e "\033[31m雞蛋面\033[0m"
24 ;;
25 *)
26 echo -e "\033[31m sorry,你想吃的本店沒有!\033[0m"
27 ;;
28 esac
29 break
30
31
32 done
函數介紹:
函數function是由若干條shell命令組合成的語句塊,實現代碼重用和模塊化編程。
函數function與shell程序形式上是相似的,不同的是它不是一個單獨的進程,不能獨立運行,而是shell程序的一部分。
函數和shell程序比較相似,區別在于:
shell程序在子shell中運行;
而shell函數在當前shell中運行。因此在當前shell中,函數可以對shell中的變量進行修改;
定義函數:
函數由兩部分組成:函數名和函數體
語法一:
function f_name {
函數體…….
}
語法二:
f_name() {
函數體…….
}
函數的使用:
函數的定義和使用:
可在交互式環境下定義函數
可將函數放在腳本文件中作為它的一部分
可放在只包含函數的單獨文件中
調用:
函數只有被調用才會執行;
調用:給定函數名
函數名出現的地方,會被自動替換為函數代碼
函數的生命周期:
函數被調用時創建,返回時終止;
函數返回值:
函數有兩種返回值:
函數的執行結果返回值:
使用echo或printf命令進行輸出
函數體中調用命令的輸出結果
函數的退出狀態碼:
默認取決于函數中執行的最后一條命令的退出狀態碼
自定義退出狀態碼,其格式為:
return 從函數中返回,用最后狀態命令決定返回值
return 0 無錯誤返回;
return 1-255 有錯誤返回;
使用函數文件:
可以將經常使用的函數存入函數文件,然后將函數文件載入shell;
函數文件名可以任意選取,但最好與相關任務有某種聯系。例如:function.main;
一旦函數文件載入shell,就可以在命令行或腳本中調用函數,可以使用set命令查看所有定義的函數,其輸出列表包括已經載入shell的所有函數。
若要改動函數,首先使用unset命令從shell中刪除函數,改動完畢后,在重新載入此文件;
載入函數:
函數文件已創建好,要將它載入shell
定義函數文件并載入shell的格式:
. function.main 或 source function.main要使用正確的路徑
set命令檢查函數是否已載入,set命令將在shell中顯示所有的載入函數。
刪除shell函數:
現在對函數做一些改動,首先刪除函數,使其對shell不可用。使用unset命令完成此功能;
命令格式:
unset function_name
函數參數:
函數可以接受參數:
傳遞參數給函數:調用函數時,在函數名后以空白分隔給定參數列表即可;例如:testfunc arg1 arg2 arg3
在函數體中,可以使用$1,$2 ……. 調用這些參數;還可以使用$@,$#等特殊變量;
函數變量:
變量作用域:
環境變量:當前shell和子shell有效;
本地變量:只在當前shell進程有效,為執行腳本會啟動專用子shell進程;因此,本地變量的作用域范圍是當前shell腳本進程文件,包括腳本中函數。
局部變量:函數的生命周期;函數結束時變量被自動銷毀;
注意:如果函數中有局部變量,如果其名同本地變量,使用局部變量;
在函數中定義局部變量的方法:
local name=value
函數遞歸實例:
函數遞歸:
函數直接或間接調用自身
需注意遞歸層數
示例:
函數遞歸階乘運算
1 #!/bin/bash
2 #
3
4 fact () {
5 if [ $1 -eq 0 -o $1 -eq 1 ];then
6 echo 1
7 else
8 echo $(($1*`fact $[$1-1]`))
9 fi
10 }
11
12 fact $1
示例:
在腳本中定義及使用函數
1 #!/bin/bash
2 #fun1
3 #zheng
4 #加減乘除函數庫!
5
6 jia() {
7 sum=$[$1+$2]
8 echo "$sum"
9 }
10
11 jian() {
12 sum=$[$1-$2]
13 echo "$sum"
14 }
15
16 cheng() {
17 sum=$[$1*$2]
18 echo "$sum"
19 }
20
21
22 chu() {
23 sum=$[$1/$2]
24 echo "$sum"
25 }
定義數組:
程序=指令+數據
變量:存儲單個元素的內存空間;
數組:存儲多個元素的連續的內存空間;
數組名:整個數組只有一個名字;
數組索引:標號從0開始;
數組名[索引]
${ARRAY_NAME[INDEX]}
注:bash-4及之后的版本,支持自定義索引格式,而不僅僅是0,1,2,3….數組格式,此類數組稱之為關聯數組;
聲明數組:
declare -a ARRAY_NAME 聲明索引數組
declare -A ARRAY_NAME 聲明關聯數組
數組中元素的賦值方式;
(1)一次只賦值一個元素;
ARRAY_NAME[INDEX]=value
例:
[root@centos7 ~]# dongwu[0]=pig
[root@centos7 ~]# dongwu[1]=dog
[root@centos7 ~]# echo $dongwu
pig
[root@centos7 ~]# echo ${dongwu[1]}
dog
[root@centos7 ~]# echo ${dongwu[0]}
pig
[root@centos7 ~]#
(2)一次賦值全部元素;
ARRAY_NAME=(“val1” “val2” “val3” “val4”…….)
例:
[root@centos7 ~]# weekday=("monday" "tuesday" "wednesday")
[root@centos7 ~]# echo ${weekday[0]}
monday
[root@centos7 ~]# echo ${weekday[1]}
(3)只賦值特定元素
ARRAY_NAME=([0]=”val1” [3]=”val2”…..)
注:bash支持稀疏格式的數組;
例:
[root@centos7 ~]# gongsi=([1]=baidu [3]=tengxun [4]=ali)
[root@centos7 ~]# echo ${gongsi[3]}
tengxun
[root@centos7 ~]#
(4)read -a ARRAY_NAME
例:
[root@centos7 ~]# read -a jiaotong
huoche qiche feiji kunchuan
[root@centos7 ~]# echo ${jiaotong[0]}
huoche
[root@centos7 ~]#
引用數組中的元素:${ARRAY_NAME[INDEX]}
注意:引用時,只給數組名,表示引用下標為0的元素;
數組的長度(數組中元素的個數)
${#ARRAY_NAME[*]} 表示查看數組中的元素個數;
${#ARRAY_NAME[@]}表示查看數組中的元素個數;
例:
[root@centos7 ~]# echo ${#jiaotong[*]}
4
[root@centos7 ~]#
${ARRAY_NAME[*]} 表示查看數組中的所有元素
${ARRAY_NAME[@]} 表示查看數組中的所有元素
例:
[root@centos7 ~]# echo ${jiaotong[*]}
huoche qiche feiji kunchuan
[root@centos7 ~]#
注意:如果寫成${#ARRAY_NAME} 表示查看數組中第一元素的字符長度;
示例:生成10個隨機數,并找出其中的最大值;
1 #!/bin/bash
2 #zheng
3 #
4
5 declare -a rand
6 declare -i max=0
7 for i in {0..9};do
8
9 rand[$i]=$RANDOM
10 echo ${rand[$i]}
11 if [ ${rand[$i]} -gt $max ];then
12 max=${rand[$i]}
13 fi
14 done
15 echo "max : $max"
16 unset rand
17 unset i
示例:定義一個數組,數組中的元素是/var/log目錄下所有以*.log結尾的文件,統計其下標為偶數的文件中的行數之和;
1 #!/bin/bash
2 #zheng
3 #
4 declare -a files
5 files=(/var/log/*.log)
6 declare -i lines=0
7
8 for i in $(seq 0 $[${#files[@]}-1]);do
9
10 if [ $[$i%2] -eq 0 ];then
11 let lines+=$(wc -l ${files[$i]} | cut -d " " -f1)
12 fi
13 done
14 echo "lines :$lines"
15 unset files
16 unset lines
17 unset i
數組元素切片:
${ARRAY_NAME[@]:offset:number}
offset:要跳過的元素個數;
number:要取出的元素個數;省略number時,表還取偏移量之后的所有元素;
向非稀疏格式數組中追加元素:
ARRAY_NAME[${#array_name[]*}]=value
例:
[root@centos7 testdir]# echo ${weekday[*]}
monday tuesday wednesday
[root@centos7 testdir]# weekday[${#weekday[@]}]=sunday
[root@centos7 testdir]# echo ${weekday[*]}
monday tuesday wednesday sunday
[root@centos7 testdir]#
刪除數組中的某個元素:
unset ARRAY[INDEX]
例:
[root@centos7 testdir]# unset weekday[3]
關聯數組:
declare -A ARRAY_NAME (使用關聯數組必須提前聲明)
ARRAY_NAME=([index_name1]=value1 [index_name2]=value2)
bash的內置字符串處理工具:
字符串切片:
${var:offset:number}
offset:要跳過的元素個數;
number:要取出的元素個數;省略number時,表還取偏移量之后的所有元素;
取自符串的字串;
取字符串的最右側的幾個字符:${var: -length}
注意:冒號后必須有一個空白字符;
例:
[root@centos7 testdir]# echo ${weekday[*]}
monday tuesday wednesday sunday
[root@centos7 testdir]# echo ${weekday[@]:1:3}
tuesday wednesday sunday
[root@centos7 testdir]# echo ${weekday[@]: -1}
sunday
[root@centos7 testdir]#
基于模式取字串:
${var#*word}:其中Word是指定的分隔符;功能:自左而右,查找var變量所存儲的字符串中,第一次出現的word分隔符,刪除字符串開頭至此分隔符之間的所有字符;
${var##*word}:其中Word是指定的分隔符;功能:自左而右,查找var變量所存儲的字符串中,最后一次出現的word分隔符,刪除字符串開頭至此分隔符之間的所有字符;
示例:
[root@centos7 testdir]# path=/etc/init.d/functions
[root@centos7 testdir]# echo ${path#*/}
etc/init.d/functions
[root@centos7 testdir]# echo ${path##*/}
functions
[root@centos7 testdir]#
${var%word*}:其中Word是指定的分隔符;功能:自右而左,查找var變量所存儲的字符串中,第一次出現的word分隔符,刪除此字符串至尾部的所有字符;
${var%%word*}:其中Word是指定的分隔符;功能:自右而左,查找var變量所存儲的字符串中,最后一次出現的word分隔符,刪除此字符串至尾部的所有字符;
示例:
[root@centos7 testdir]# path=/etc/init.d/functions
[root@centos7 testdir]# echo ${path%/*}
/etc/init.d
[root@centos7 testdir]# echo ${path%%/*}
[root@centos7 testdir]#
查找替換:
${var/PATTERN/SUBSTI}:查找var所表示的字符串,第一次被PATTERN所匹配的字符串,將其替換為SUBSTI所表示的自符串;
${var//PATTERN/SUBSTI}:查找var所表示的字符串,所有被PATTERN所匹配的字符串,將其全部替換為SUBSTI所表示的自符串;
示例:
[root@centos7 testdir]# name="root:x:0:0::root:bashroot"
[root@centos7 testdir]# echo ${name/root/ROOT}
ROOT:x:0:0::root:bashroot
[root@centos7 testdir]# echo ${name//root/ROOT}
ROOT:x:0:0::ROOT:bashROOT
[root@centos7 testdir]#
${var/#PATTERN/SUBSTI} 查找var所表示的字符串中,行首被PATTERN所匹配到的字符串,將其替換為SUBSTI所表示的字符串;
${var/%PATTERN/SUBSTI} 查找var所表示的字符串中,行尾被PATTERN所匹配到的字符串,將其替換為SUBSTI所表示的字符串;
示例:
[root@centos7 testdir]# name="root:x:0:0::root:bashroot"
[root@centos7 testdir]# echo ${name/#root/ROOT}
ROOT:x:0:0::root:bashroot
[root@centos7 testdir]# echo ${name/%root/ROOT}
root:x:0:0::root:bashROOT
[root@centos7 testdir]#
注意:PATTERN中使用glob風格的通配符;
查找刪除:
${var/PATTERN}:以PATTERN為模式查找var字符串中第一次的匹配,并刪除;
${var//PATTERN}:以PATTERN為模式查找var字符串中所有的匹配,并刪除;
${var/#PATTERN}:以PATTERN為模式查找var字符串中行首匹配,并刪除;
${var/%PATTERN}:以PATTERN為模式查找var字符串中行尾匹配,并刪除;
示例:
[root@centos7 testdir]# name="root:x:0:0::root:bashroot"
[root@centos7 testdir]# echo ${name/root}
:x:0:0::root:bashroot
[root@centos7 testdir]# echo ${name//root}
:x:0:0:::bash
[root@centos7 testdir]# echo ${name/#root}
:x:0:0::root:bashroot
[root@centos7 testdir]# echo ${name/%root}
root:x:0:0::root:bash
[root@centos7 testdir]#
字符大小寫轉換:
${var^^}:把var中的所有小寫字符轉換為大寫;
${var,,}:把var中的所有大寫字符轉換為小寫;
示例:
[root@centos7 testdir]# name="root:x:0:0::root:bashroot"
[root@centos7 testdir]# echo ${name^^}
ROOT:X:0:0::ROOT:BASHROOT
[root@centos7 testdir]# name1=${name^^}
[root@centos7 testdir]# echo $name1
ROOT:X:0:0::ROOT:BASHROOT
[root@centos7 testdir]# echo ${name,,}
root:x:0:0::root:bashroot
[root@centos7 testdir]#
變量賦值:
${var:-VALUE}:如果var變量為空,或未設置,那么返回value,否則返回var變量的值;
${var:=VALUE}:如果var變量為空,或未設置,那么返回value,并將value賦值給var變量;否則,則返回var變量的值;
${var:+VALUE}:如果var變量不空,則返回value
${var:?ERROR_INFO}:如果var為空,或未設置,那么返回ERROR_INFO為錯誤提示,否則,返回var值;
高級變量用法:
shell變量一般是無類型的,但是bash shell提供了declare和typeset兩個命令用于指定變量的類型,兩個命令是完全等價的
declare [options] 變量名
-r:將變量設置為只讀變量;
-i:將變量定義為整數型變量;
-a:將變量定義為數組;
-f:顯示此腳本前定義過的所有函數名及其內容;
-F:僅顯示此腳本前定義過的所有函數名;
-x:將變量聲明為環境變量;
-l:將變量值轉為小寫字母;
-u:將變量值轉換為大寫字母;
間接變量引用:
如果第一個變量的值是第二個變量的名字,從第一個變量引用第二個變量的值,就稱為間接變量引用;
variable1=variable2
variable2=value
分析:variable1的值時variable2,而variable2又是變量名,variable2的值為value,間接變量引用是指通過variable1獲得變量值value的行為;
bash shell提供了兩種格式實現間接變量引用;
eval tempvar=\$$variable1
tempvar=${!variabe1}
示例:
[root@centos7 testdir]# v1=v2
[root@centos7 testdir]# v2=mage
[root@centos7 testdir]# echo ${!v1}
mage
[root@centos7 testdir]#
或
[root@centos7 testdir]# v1=v2
[root@centos7 testdir]# v2=mage
[root@centos7 testdir]# eval v3=\$$v1
[root@centos7 testdir]# echo $v3
mage
[root@centos7 testdir]#
eval命令:
eval命令將會首先掃描命令行進行所有的置換,然后在執行該命令。該命令適用于那些一次掃描無法實現其功能的變量。該命令對變量進行兩次掃描;
(eval命令:先將變量替換成命令,然后在執行該命令)
示例:
[root@centos7 testdir]# host=hostname
[root@centos7 testdir]# eval $host
centos7
[root@centos7 testdir]#
創建臨時文件:
mktemp命令:創建的臨時文件可以避免沖突,文件名后要至少跟三個大寫的XXX;
mktemp [options] [TEMPLATE]
-d:創建臨時目錄;
–tmpdir=/DIR :指明臨時文件所存放的目錄位置;
示例:
創建臨時指定目錄下的文件:
root@centos7 testdir]# mktemp –tmpdir=/testdir test.XXX
/testdir/test.7WV
[root@centos7 testdir]#
創建臨時目錄:
[root@centos7 testdir]# mktemp -d dir.XXX
dir.lKU
[root@centos7 testdir]#
安裝復制文件:
install命令:
install [options] source directory
-m:mode設置權限;默認755
-o:owner 設置屬主;
-g:group 設置屬組;
bash如何展開命令行:
把命令行分成單個命令詞;
展開別名;
展開大括號中的聲明({});
展開波浪符聲明({});
命令替換$()和 “;
再次把命令行分成命令詞;
展開文件通配(* ? [abc]等等);
準備I/O重定向(< >);
運行命令;
防止擴展:
反斜線(\)會使隨后的字符按愿意解釋
加引號來防止擴展
單引號防止所有的擴展;
雙引號也防止所有的擴展,但是以下情況例外:
$ ——變量擴展
`——–命令替換
\——–禁止單個字符擴展
!——–歷史命令替換
bash的配置文件:
按生效范圍劃分,可分為兩類:
全局配置:
/etc/profile
/etc/profile.d/*.sh
/etc/bashrc
個人配置:
~/.bash_profile
~/.bashrc
shell登錄兩種方式:
交互式登錄:
(1)直接通過終端輸入用戶名密碼登錄;
(2)使用 su – username 切換的用戶;
交互式登錄系統依次所執行的文件:
/etc/profile—–>/etc/profile.d/*.sh——->~/.bash_profile——>~/.bashrc——>/etc/bashrc
非交互式登錄:
(1)su username;
(2)圖形界面下打開終端;
(3)執行腳本;
非交互式登錄系統依次所執行的文件:
~/.bashrc—–>/etc/bashrc——–>/etc/profile.d/*.sh
profile類文件:
profile類:為交互式登錄的shell提供配置:
全局:/etc/profile /etc/profile.d/*.sh
個人:~/.bash_profile
功能:
(1)用于定義環境變量;
(2)運行命令或腳本;
bashrc類文件:
bashrc類:為非交互式和交互式登錄的shell提供配置:
全局:/etc/bashrc
個人:~/.bashrc
功能:
(1)定義本地變量
(2)定義命令別名和函數
編輯配置文件生效:
修改profile和bashrc文件后需要生效
兩種生效方法:
(1)重新啟動shell進程;
(2)使用 . 或 source 使配置文件重新加載;
bash 退出任務:
當退出登錄的shell時系統會執行~/.bash_logout文件中的內容
功能:
(1)可以創建自動備份;
(2)刪除臨時文件;
原創文章,作者:zhengyibo,如若轉載,請注明出處:http://www.www58058.com/42395