概述
腳本編程能力是作為運維工程師不可或缺的一項基本技能,各種系統的運維,如果完全靠命令行一條一條命令來執行,工作效率可想而知,而腳本卻可以將完成一定功能的各個命令依據一定的流程控制,邏輯判斷去完成某種功能,提升工作效率。本章就簡單介紹一些linux下的bash腳本編程的基礎入門知識,具體內容分為以下幾個方面:
1、變量基礎
2、運算基礎
3、條件測試
4、腳本練習
第一章 變量基礎
1、變量的基礎定義
<1>什么是變量?
變量實際就是一段命名的內存空間,存儲著可能發生變化的數據
<2>變量存儲的類型
字符型、數值型(整型、浮點型)
<3>各種編程語言對變量類型的定義要求
強類型:定義變量時必須指定類型、參與運算必須符合類型
要求;調用未聲明變量會產生錯誤
如 java,python
弱類型:無須指定類型,默認均為字符型;參與運算會自動
進行隱式類型轉換;變量無須事先定義可直接調用
如: bash 不支持浮點數
<4>變量的命名規則
a、不能使程序中的保留字:例如if, for;
b、只能使用數字、字母及下劃線,且不能以數字開頭
c、見名知義
d、統一命名規則:駝峰命名法
如:UserName 為大駝峰
userName 為小駝峰
<5>Linux上變量的分類(根據變量的生效范圍等標準)
本地變量:生效范圍為當前shell進程;對當前shell之外的其它shell進程,包括當前shell的子shell進程均無效
環境變量:生效范圍為當前shell進程及其子進程
局部變量:生效范圍為當前shell進程中某代碼片斷(通常指函數)
位置變量: $1, $2, …來表示,用于讓腳本在腳本代碼中調用通過命令行傳遞給它的參數
特殊變量: $?, $0, $*, $@, $#
2、本地變量
變量賦值: name=‘value’,
(1) 可以是直接字串; name=“root"
(2) 變量引用: name="$USER"
(3) 命令引用: name=`COMMAND`, name=$(COMMAND)
變量引用: ${name}, $name
"":弱引用,其中的變量引用會被替換為變量值
'':強引用,其中的變量引用不會被替換為變量值,而保持原字符串
顯示已定義的所有變量: set(可顯示所有的變量,包括環境變量等,還包括定義的函數)
刪除變量: unset name
3、環境變量(下級進程都能使用)
變量聲明、賦值:
export name=VALUE
declare -x name=VALUE
變量引用: $name, ${name}
顯示所有環境變量:export、env、printenv
刪除: unset name
bash有許多內建的環境變量,如:PATH, SHELL, USRE,UID,HISTSIZE, HOME, PWD,OLDPWD, HISTFILE, PS1等
4、位置參數變量
功能:在腳本代碼中調用通過命令行傳遞給腳本的參數
$1, $2, …:對應第1、第2等參數, shift [n]換位置
$0: 命令本身
$*: 傳遞給腳本的所有參數,全部參數合為一個字符串
$@: 傳遞給腳本的所有參數,每個參數為獨立字符串
$@ $* 只在被雙引號包起來的時候才會有差異
$#: 傳遞給腳本的參數的個數
示例:判斷給出的文件的行數
linecount="$(wc -l $1| cut -d' ' -f1)"
echo "$1 has $linecount lines."
變量的引用:直接$1,$2,當多位數最好用{}大括號引用起來,例如${21} 表示第21個位置參數變量
$*表示全部的參數,當做一個整體來存儲
$@表示全部的參數,將各個參數作為獨立的個體存儲
區別如下所示:
兩位數以上的位置參數變量的引用需要用{}大括號引用起來,例如
5、只讀變量
只讀變量:只能聲時,但不能修改和刪除(一般用來定義常量,例如定義pai=3.1415926),可定義為只讀變量后,可以再將其定義為環境變量,既是常量又是環境變量
只讀變量的定義:
readonly name
declare -r name
撤銷:
unset name
第二章 運算基礎
1、算數運算
bash中的算術運算:
+, -, *, /, %取模(取余) , **(乘方)
實現算術運算:
(1) let var=算術表達式
(2) var=$[算術表達式]
(3) var=$((算術表達式))
(4) var=$(expr arg1 arg2 arg3 …)
判斷變量整數:expr $VAR + 0 判斷整數
在利用expr進行乘法計算時,*要轉義,寫成\*
expr計算時,將后面計算式當做參數,故各個參數之間要有空格,引用expr結果時,要用“ 表示是命令引用
(5) declare –i var = 數值
(6) echo ‘算術表達式’ | bc
bash有內建的隨機數生成器: $RANDOM( 1-32767)
echo $[$RANDOM%50] : 0-49之間隨機數
增強型賦值:
+=, -=, *=, /=, %=
let varOPERvalue
例如:let count+=3 自加3后自賦值
自增,自減:
let var+=1
let var++
let var-=1
let var–
例如
i=100
let v=++i
v的結果為101,(先自加+后=)如果let v=i++,則結果是v=100(先=后自加+)
2、邏輯運算
與:0與任何數都得0
或:1或任何數都得1
非:取反
短路運算:
短路與:&&
第一個為0,結果必定為0;
第一個為1,第二個必須要參與運算;
短路或:||
第一個為1,結果必定為1;
第一個為0,第二個必須要參與運算;
異或:^
異或的兩個值,相同為假,不同為真
3、腳本的執行狀態結果 $?
$? 變量保存最近的命令退出狀態
一個命令是否執行成功,可以通過顯示$?的值來報告成功或失敗
0 代表成功, 1-255代表失敗
腳本退出狀態碼:(取決于腳本最后一條命令的執行狀態結果)
exit [n]:自定義退出狀態碼;n的值為0-255之間
注意:腳本中一旦遇到exit命令,腳本會立即終止;終止退出狀態取決于exit命令后面的數字
注意:如果未給腳本指定退出狀態碼,整個腳本的退出狀態碼取決于腳本中執行的最后一條命令的狀態碼
4、運行腳本的不同方式的區別
. 和source執行腳本時:沒有開子進程執行腳本,相當于直接在shell里面運行腳本里面的語句,故運行完腳本,腳本里面的變量在shell里依然有效
bash和執行權限執行腳本:開了個子進程執行腳本,故腳本里面定義的變量,無法在shell里面繼續生效
腳本里面某一條語句如果用()括號括起來,則表示該條語句新建一個子進程進行執行,執行完成后結果返回腳本里面
第三章 條件測試
1、測試命令:
test EXPRESSION
[ EXPRESSION ]
[[ EXPRESSION ]],一般字符串匹配都用這個
注意: EXPRESSION前后必須有空白字符
[[ $VAR ]] 可判斷變量是否有定義
根據退出狀態而定,命令可以有條件地運行
&& 代表條件性的AND THEN
|| 代表條件性的OR ELSE
2、數值測試:
-gt: 是否大于;
-ge: 是否大于等于;
-eq: 是否等于;
-ne: 是否不等于;
-lt: 是否小于;
-le: 是否小于等于;
3、字符串測試:
==:是否等于;
>: ascii碼是否大于ascii碼
<: 是否小于
!=: 是否不等于
=~: 左側字符串是否能夠被右側的PATTERN所匹配
注意: 此表達式一般用于[[ ]]中;
-z "STRING":字符串是否為空,空為真,不空為假
-n "STRING":字符串是否不空,不空為真,空為假
注意:用于字符串比較時的用到的操作數都應該使用引號
4、文件測試:
存在性測試
-a FILE:同-e
-e FILE: 文件存在性測試,存在為真,否則為假;
存在性及類別測試
-b FILE:是否存在且為塊設備文件;
-c FILE:是否存在且為字符設備文件;
-d FILE:是否存在且為目錄文件;
-f FILE:是否存在且為普通文件;
-h FILE 或 -L FILE:存在且為符號鏈接文件;
-p FILE:是否存在且為命名管道文件;
-S FILE:是否存在且為套接字文件;
文件權限測試:
-r FILE:是否存在且可讀,判斷當前用戶對指定的文件是否有讀權限
-w FILE: 是否存在且可寫,判斷當前用戶對指定的文件是否有寫權限
-x FILE: 是否存在且可執行,判斷當前用戶對指定的文件是否有執行權限
文件特殊權限測試:
-g FILE:是否存在且擁有sgid權限;
-u FILE:是否存在且擁有suid權限;
-k FILE:是否存在且擁有sticky權限;
文件大小測試:
-s FILE: 是否存在且非空;
文件是否打開:
-t fd: fd表示文件描述符是否已經打開且與某終端相關
-N FILE:文件自上一次被讀取之后是否被修改過
-O FILE:當前有效用戶是否為文件屬主
-G FILE:當前有效用戶是否為文件屬組
雙目測試:
FILE1 -ef FILE2: FILE1與FILE2是否指向同一個設備上的相同inode
FILE1 -nt FILE2: FILE1是否新于FILE2;比較mtime
FILE1 -ot FILE2: FILE1是否舊于FILE2;比較mtime
5、組合測試條件
第一種方式:
COMMAND1 && COMMAND2 并且
COMMAND1 || COMMAND2 或者
! COMMAND 非
如: [ -e FILE ] && [ -r FILE ]
第二種方式:
EXPRESSION1 -a EXPRESSION2 并且
EXPRESSION1 -o EXPRESSION2 或者
! EXPRESSION
必須使用測試命令進行;
# [ -z “$HOSTNAME” -o $HOSTNAME "=="localhost.localdomain" ] && hostname www.nwc.com
# [ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab
第四章 腳本練習
1、編寫腳本/root/bin/systeminfo.sh,顯示當前主機系統信息,包括主機名,IPv4地址,操作系統版本,內核版本,CPU型號,內存大小,硬盤大小。
#!/bin/bash # Autor:nwc # Version:1.0 # CreateTime:2016-08-11 # Description:show the system info CPU=`cat /proc/cpuinfo |grep "model name"|cut -d ":" -f2 |head -1` HNAME=`hostname` IP=`ifconfig|sed -n '2p'|cut -d: -f2|cut -d" " -f1` OSRELEASE=`uname -sr` KERNEL=`uname -r` MEM=`cat /proc/meminfo|grep -i "memtotal"|tr -s ' '|cut -d: -f2` DISKSIZE=`fdisk -l|grep "Disk /dev/[sh]d"|cut -d: -f2|cut -d" " -f2|awk '{sum+=$1}END{print sum}'` echo "Hostname is: $HNAME" echo "IPv4 Address is: $IP" echo "OSRelease is: $OSRELEASE" echo "Kernel is: $KERNEL" echo "CPU is: $CPU" echo "MemSize is: $MEM" echo "DiskSize is: $DISKSIZE GiB" unset CPU unset HNAME unset IP unset OSRELEASE unset KERKNEL unset MEM unset DISKSIZE
運行結果為:
2、編寫腳本/root/bin/backup.sh,可實現每日將/etc/目錄備份到/root/etcYYYY-mm-dd中
#!/bin/bash # Autor:nwc # Version:1.0 # CreateTime:2016-08-11 # Description:backup etc to /root/etcYYYY-mm-dd cp -a /etc /root/etc`date +%F` && echo "backup etc success" || echo "backup etc fail"
運行結果為:
3、編寫腳本/root/bin/disk.sh,顯示當前硬盤分區中空間利用率最大的值
#!/bin/bash # Autor:nwc # Version:1.0 # CreateTime:2016-08-11 # Description:show the max used disk MaxDiskUsed=`df|grep "/dev/[sh]d"|tr -s ' ' '%'|cut -d% -f5|sort -nr|head -1` echo "Max Disk Used(%) is: $MaxDiskUsed" unset MaxDiskUsed
運行結果為:
4、編寫腳本/root/bin/links.sh,顯示正連接本主機的每個遠程主機的IPv4地址和連接數,并按連接數從大到小排序
#!/bin/bash # Autor:nwc # Version:1.0 # CreateTime:2016-08-11 # Description:show links LINK=`netstat -tn|grep "^tcp"|tr -s ' '|cut -d" " -f5|cut -d: -f1|grep -v "^$"|uniq -c|sort -nr` echo "$LINK" unset LINK
運行結果為:
5、寫一個腳本/root/bin/sumid.sh,計算/etc/passwd文件中的第10個用戶和第20用戶的ID之和
#!/bin/bash # Autor:nwc # Version:1.0 # CreateTime:2016-08-11 # Description:10 and 20 user UID sum # sumid=`sed -n -e '10p' -e '20p' /etc/passwd|cut -d: -f3|awk '{sum+=$1}END{print sum}'` id10=`sed -n '10p' /etc/passwd | cut -d: -f3` id20=`sed -n '20p' /etc/passwd | cut -d: -f3` sumid=$[${id10}+${id20}] echo "10&20 UID sum $sumid" unset id10 unset id20 unset sumid
運行結果為:
6、寫一個腳本/root/bin/sumspace.sh,傳遞兩個文件路徑作為參數給腳本,計算這兩個文件中所有空白行之和
#!/bin/bash # Autor:nwc # Version:1.0 # CreateTime:2016-08-11 # Description: $1 and $2 blank lines sum space1=`grep "^$" $1|wc -l` space2=`grep "^$" $2|wc -l` sum=$[${space1}+${space2}] echo "$1 $2 blank lines sum is $sum" unset space1 unset space2 unset sum
運行結果為:
7、寫一個腳本/root/bin/sumfile.sh,統計/etc, /var, /usr目錄中共有多少個一級子目錄和文件
#!/bin/bash # Autor:nwc # Version:1.0 # CreateTime:2016-08-11 # Description: ETC=`ls /etc|wc -l` VAR=`ls /var|wc -l` USR=`ls /usr|wc -l` sum=$[$ETC+$VAR+$USR] echo "sum is $sum" unset ETC unset VAR unset USR unset sum
運行結果為:
8、寫一個腳本/root/bin/argsnum.sh,接受一個文件路徑作為參數;如果參數個數小于1,則提示用戶“至少應該給一個參數”,并立即退出;如果參數個數不小于1,則顯示第一個參數所指向的文件中的空白行數
#!/bin/bash # Autor:nwc # Version:1.0 # CreateTime:2016-08-11 # Description: [ $# -lt 1 ] && echo "at least one argu" || echo " $1 blank lines is `grep "^$" $1|wc -l`"
運行結果為:
9、寫一個腳本/root/bin/hostping.sh,接受一個主機的IPv4地址做為參數,測試是否可連通。如果能ping通,則提示用戶“該IP地址可訪問”;如果不可ping通,則提示用戶“該IP地址不可訪問”
#!/bin/bash # Autor:nwc # Version:1.0 # CreateTime:2016-08-11 # Description: ping -c1 -W1 $1 &>/dev/null && echo "$1 is up" || echo "$1 is down"
執行結果為:
10、chmod -rw /tmp/file1,編寫腳本/root/bin/per.sh,判斷當前用戶對/tmp/fiile1文件是否不可讀且不可寫
#!/bin/bash # Autor:nwc # Version:1.0 # CreateTime:2016-08-11 # Description: [ ! -r /tmp/file1 -a ! -w /tmp/file1 ] && echo "have no right rw" || echo "have right r or w or rw"
運行結果為:
11、編寫腳本/root/bin/nologin.sh和login.sh,實現禁止和充許普通用戶登錄系統。
#!/bin/bash # Autor:nwc # Version:1.0 # CreateTime:2016-08-11 # Description: nologin [ -f /etc/nologin ] && echo "already can not access" || (touch /etc/nologin && echo "create /etc/nologin success")
nologin的執行結果
#!/bin/bash # Autor:nwc # Version:1.0 # CreateTime:2016-08-11 # Description:login [ -f /etc/nologin ] && (rm -f /etc/nologin ; echo "delete /etc/nologin success") || echo "already can access"
login執行結果
12、寫一個腳本/root/bin/hostping.sh,接受一個主機的IPv4地址做為參數,先判斷是否合格IP,否,提示IP格式不合法并退出,是,測試是否可連通。如果能ping通,則提示用戶“該IP地址可訪問”;如果不可ping通,則提示用戶“該IP地址不可訪問”
#!/bin/bash # Autor:nwc # Version:1.0 # CreateTime:2016-08-11 # Description: ping a IP addr echo "$1"|grep -E "\<(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[1-4][0-9]|25[0-5])\.){3} ([0-9]|[1-9][0-9]|1[0-9][0-9]|2[1-4][0-9]|25[0-5])\>" &>/dev/null && (ping -c1 -W1 $1 &>/dev/null && echo "$1 is up" || echo "$1 is down") || echo "$1 is not a IP addr"
執行結果如下:
13、計算1+2+3+…+100的值
#!/bin/bash # Autor:nwc # Version:1.0 # CreateTime:2016-08-11 # Description:the sum of all args echo "`echo "$@"|tr -s ' ' '+'`"|bc
執行結果如下:
14、計算從腳本第一參數A開始,到第二個參數B的所有數字的總和,判斷B是否大于A,否提示錯誤并退出,是則計算之
#!/bin/bash # Autor:nwc # Version:1.0 # CreateTime:2016-08-11 # Description: sum between arg1 to arg2 [ $2 -ge $1 ] && seq $1 $2|tr -s '\n' '+'|sed -r 's@(.*)\+$@\1\n@'|bc || echo "Error args"
運行結果為:
原創文章,作者:M20-1倪文超,如若轉載,請注明出處:http://www.www58058.com/33512
只讀變量不能銷毀
寫的很詳細,態度很端正,對各位置變量,通過腳本來進行驗證,思路也很清晰,再接再厲。