shell腳本編程:
編程基礎
程序:指令+數據
編程語言的分類:根據運行方式
編譯運行:源代碼–>編譯器(編譯)–>程序文件
解釋運行:源代碼–>運行時啟動解釋器,由解釋器邊解釋邊運行;
根據其編程過程中功能的實現是調用庫還是調用外部的程序文件
shell腳本編程
利用系統上的命令及編程組件進行編程
完整編程;
利用庫或編程組件進行編程
編程模式:
面向過程的編程語言
以指令為中心來組織代碼,數據是服務于代碼的;
順序執行
選擇執行
循環執行
代表:c bash
面向對象的編程語言
以數據為中心來組織代碼,圍繞數據開組織指令;
類(class):實例化對象,method;
代表:java c++ python
shell腳本編程:過程式編程,解釋運行,依賴于外部程序文件運行;
作用:
自動化常用命令
執行系統管理和故障排除
創建簡單的應用程序
處理文本或文件
1如何寫shell腳本
腳本文件第一行,頂格;給出shell類型,解釋器路徑,用于指明執行當前腳本的解釋器程序文件
常見解釋器:
#!/bin/bash
#!/bin/python
#!/bin/perl
第二步,寫腳本正文
#author:創作者
#Version:版本號
#Description:功能描述
#time:時間
第三步:運行腳本
給予執行權限,在命令行上指定腳本的絕對或相對路徑 chmod+x
直接運行解釋器,將腳本作為解釋器程序的參數運行 ./file
2語法檢查
bash -n /path/to/some_script
3腳本調試執行(顯示執行過程)
bash -x /path/to/some_script
變量
程序:指令+程序
指令:有程序文件提供
數據:IO設備給出標準輸入 ,文件,管道,變量
程序:算法+數據結構
變量:變量名+指向的空間空間
作用:
1,數據存儲格式;
2.參與的運算
3.表示的數據范圍
數據存儲方式(類型):
字符:
數值: 整型,浮點型
數值類型 | 所占字符數 | 取值范圍 |
byte | 1 | 0-255 |
short | 2 | 65535 |
int | 4 | 40億 |
booleam | ||
long | 4 | |
float | 4 | |
double | 8 | |
chart |
變量類型:存儲格式,表示數據范圍,參與的運算
編程語言:
強類型變量:
定義變量時必須指定類型,參與運算必須符合類型
要求, 調用未聲明變量會產生錯誤
例: C C++ java python
弱類型變量:
無需指定類型,默認均為字符型,;參與運算時會自動進行隱形類型轉換,連梁無需事先定義可直接調用
bash 把所有變量統統是做字符類型;
bash不支持浮點類型數據
bash中變量無需事先聲明,相當于,把聲明和賦值過程同時實現。
聲明:類型 變量名
(shell)變量賦值:name=value(值)
變量替換;把變量名出現的位置替換為其所指向的內存空間中數據;
變量引用:${var_name},$var_name
變量名命名方式:
1.變量只能包含數字,字母和下劃線;不能以數字開頭;
2 不能使用程序關鍵字,if else
3.見名知意
4,統一命名法:駝峰命名法
bash變量類型:pstree 進程樹
本地變量:作用域為當前shell進程,對當前shell外的其他shell進程,包括當前shell的子shell進場June無效
變量賦值:name=value(值)
變量引用:${name},$nameo
"":變量名會替換為其值
'':變量名不會替換為其值
查看變量:set
撤銷變量:unset name (釋放是個良好的習慣,編寫腳本主動釋放)
注意:此處非變量引用
echo 變量(命令) 默認顯示為一行 echo "變量(命令)" 顯示命令原有的輸出格式
環境變量:作用域為當前shell進程及子進程
變量賦值:
(1)export name=value(值)
(2)name=value(值)
export name}
(3)declare -x name=value(值)
(4)name=value(值)
declare -x name
變量引用:${name},$name
注意:bash內嵌了許多環境變量(通常為全大寫字符),用于定義bash的工作環境
系統自帶變量(可直接引用):PWD USER OLDPWD HISTSIZE HISTCONTROL PATH, SHELL,UID,HOME,OLDPWD, HISTFILE, PS1
查看環境變量:export declare -x printenv env
撤銷變量:unset name
只讀變量:
(1)declare – r name=value
declare – rx name =value 定義常量
(2)readonly name
只讀變量無法重新賦值,并且不支持撤銷,存活時間為當前shell進程的生命周期,隨shell的終止而撤銷
局部變量:作用域為當前shell進場中某代碼片段(函數)
位置參數變量:
向執行腳本的shell進程傳遞的參數 $1, $2, …來表示,用于讓腳本在腳本代碼
$0,:命令 本身
$*: 傳遞給腳本的所有參數,全部參數合為一個整體
$@,傳遞給腳本的所有參數,每個參數為獨立字符串
注: $@ $* 只有在被雙引號包起來的時候有區別
$#:傳遞給腳本的參數的個數
輪替:
shift [n]: 位置變量輪替,踢掉參數的值,后面的值移動到前一位位置參數
示例:判斷給出的文件的行數
linecount="$(wc -l $1| cut -d' ' -f1)"
echo "$1 has $linecount lines."
中調用通過命令行傳遞給它的參數
特殊變量:shell內置的有特殊功用的變量
$?:執行狀態返回值
0:成功
1-255:失敗
默認是腳本中執行的最后一條命令的狀態返回值
自定義站臺返回值:
exit [n]:n為自己指定的狀態碼
注意:shell進程遇到exit是,會終止,整個腳本執行即為結束
例:id user3 &>/dev/null &&exit 0|useradd user3
算數運算
bash中的算術運算:help let
+, -, *, /, %取模(取余) , **(乘方)
實現算術運算:
(1) let var=算術表達式
(2) var=$[算術表達式]
(3) var=$((算術表達式))
(4) var=$(expr arg1 arg2 arg3 …)
(5) declare –i var = 數值
(6) echo ‘算術表達式’ | bc
expr $var+0 判斷數值是否是整數
expr 運算乘法 乘法符號需要加轉義字符 例 expr 2 \* 3
乘法符號有些場景中需要轉義, 如*
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–
邏輯運算:
true, false
1, 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
短路運算:
短路與:
第一個為0,結果必定為0;
第一個為1,第二個必須要參與運算;
短路或:
第一個為1,結果必定為1;
第一個為0,第二個必須要參與運算;
異或: ^
異或的兩個值,相同為假,不同為真
聚集命令:
有兩種聚集命令的方法:
? 復合式: date; who | wc -l
命令會一個接一個地運行
? 子shell: (date; who | wc -l ) >>/tmp/trace
所有的輸出都被發送給單個STDOUT和STDERR
退出狀態:
進程使用退出狀態來報告成功或失敗
? 0 代表成功, 1-255代表失敗
? $? 變量保存最近的命令退出狀態
例如:
$ ping -c1 -W1 hostdown &> /dev/null
$ echo $?
退出狀態碼:
bash自定義退出狀態碼
exit [n]:自定義退出狀態碼;
注意:腳本中一旦遇到exit命令,腳本會立即終止;終止退出
狀態取決于exit命令后面的數字
注意:如果未給腳本指定退出狀態碼,整個腳本的退出狀態碼
取決于腳本中執行的最后一條命令的狀態碼
條件測試:
bash自定義退出狀態碼
exit [n]:自定義退出狀態碼;
注意:腳本中一旦遇到exit命令,腳本會立即終止;終止退出
狀態取決于exit命令后面的數字
注意:如果未給腳本指定退出狀態碼,整個腳本的退出狀態碼
取決于腳本中執行的最后一條命令的狀態碼
條件性的執行操作:
根據退出狀態而定,命令可以有條件地運行
? && 代表條件性的AND THEN
? || 代表條件性的OR ELSE
? 例如:
$ grep -q no_such_user /etc/passwd \
|| echo 'No such user'
No such user
$ ping -c1 -W2 station1 &> /dev/null \
> && echo "station1 is up" \
> || (echo 'station1 is unreachable'; exit 1)
station1 is up
tset命令:
長格式的例子:
$ test "$A" == "$B" && echo "Strings are equal"
$ test “$A” -eq “$B” \
&& echo "Integers are equal"
? 簡寫格式的例子:
$ [ "$A" == "$B" ] && echo "Strings are equal"
$ [ "$A" -eq "$B" ] && echo "Integers are equal
bash的測試類型:
數值測試:
-gt: 是否大于;
-ge: 是否大于等于;
-eq: 是否等于;
-ne: 是否不等于;
-lt: 是否小于;
-le: 是否小于等于;
字符串測試:
==:是否等于;
>: ascii碼是否大于ascii碼
<: 是否小于
!=: 是否不等于
=~: 左側字符串是否能夠被右側的PATTERN所匹配
注意: 此表達式一般用于[[ ]]中;
-z "STRING":字符串是否為空,空為真,不空為假
-n "STRING":字符串是否不空,不空為真,空為假
注意:用于字符串比較時的用到的操作數都應該使用引號
文件測試:
存在性測試
-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;
FILE1 -ot FILE2: FILE1是否舊于FILE2;
組合測試條件
雙目測試:
FILE1 -ef FILE2: FILE1與FILE2是否指向同一個設
備上的相同inode
FILE1 -nt FILE2: FILE1是否新于FILE2;
FILE1 -ot FILE2: FILE1是否舊于FILE2;
組合測試條件:
第一種方式:
COMMAND1 && COMMAND2 并且
COMMAND1 || COMMAND2 或者
! COMMAND 非
如: [ -e FILE ] && [ -r FILE ]
? 第二種方式:
EXPRESSION1 -a EXPRESSION2 并且
EXPRESSION1 -o EXPRESSION2 或者
! EXPRESSION
必須使用測試命令進行;
# [ -z “$HOSTNAME” -o $HOSTNAME "==\
"localhost.localdomain" ] && hostname www.magedu.com
# [ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab
使用read命令來接受輸入:
使用read來把輸入值分配給一個或多個shell變量:
-p 指定要顯示的提示
-t TIMEOUT
read 從標準輸入中讀取值,給每個單詞分配一個變量
所有剩余單詞都被分配給最后一個變量
read -p “Enter a filename: “ FILE
練習:
1、編寫腳本/root/bin/systeminfo.sh,顯示當前主機系統信息,包括主機名,IPv4地址,操作系統版本,內核版本,CPU型號,內存大小,硬盤大小。
[root@wen-7 shangkelianxi]# cat sh01.sh #!/bin/bash clear echo "顯示當前主機信息:" echo "主機名:`hostname`" echo "IPV4地址:` ifconfig eno16777736| grep "inet\>"|tr -s "[[:space:]]" ":"| cut -d: -f3`" echo "操作系統版本:`cat /etc/centos-release | grep -v "^$" `" echo "內核版本: `uname -r`" echo "CPU型號: `cat /proc/cpuinfo | grep "^model name"| cut -d: -f2`" echo "內存大小:`free -h|grep "^Mem" |tr -s " " ':'| cut -d: -f2`" echo "硬盤大小: `fdisk -l| grep ".*/dev/sda\>"`" [root@wen-7 shangkelianxi]# bash sh01.sh 顯示當前主機信息: 主機名:wen-7 IPV4地址:172.18.19.219 操作系統版本:CentOS Linux release 7.2.1511 (Core) 內核版本: 3.10.0-327.el7.x86_64 CPU型號: Intel(R) Core(TM) i5-4210M CPU @ 2.60GHz 內存大小:977M 硬盤大小: 磁盤 /dev/sda:21.5 GB, 21474836480 字節,41943040 個扇區
2、編寫腳本/root/bin/backup.sh,可實現每日將/etc/目錄備份到/root/etcYYYY-mm-dd中(配合計劃任務完成)
備份/etc/到/root/etcYY-MM-DD 并檢查文件是否備份成功! backup /root/etc2016-08-12-08-12 ing /root/etc2016-08-12-08-12 is exit,no cp /etc [root@wen-7 shangkelianxi]# cat sh02.sh #!/bin/bash clear echo "備份/etc/到/root/etcYY-MM-DD 并檢查文件是否備份成功!" time1=`date +%d` dirname=/root/etc`date +%F-%m-%d` echo "backup $dirname ing" && cp -a /etc/ $dirname [ -f $dirname ] && echo " backup %dirname over "|| echo "$dirname is exit,no cp /etc"
3、編寫腳本/root/bin/disk.sh,顯示當前硬盤分區中空間利用率最大的值
顯示當前硬盤分區中空間利用率最大的值:32% [root@wen-7 shangkelianxi]# cat sh03.sh #!/bin/bash clear num=`df -h| tr -s ' ' ':'| cut -d: -f1,5| grep ':[0-9]'| sort -t: -k2 -n| tail -n1` unmn=` df | grep '/dev/sd' |sed -r 's/^.* ([0-9]+%).*/\1/' |sort -nr|head -1` echo "顯示當前硬盤分區中空間利用率最大的值:$unmn"
4、編寫腳本/root/bin/links.sh,顯示正連接本主機的每個遠程主機的IPv4地址和連接數,并按連接數從大到小排序
顯示正連接本主機的每個遠程主機的連接數和IPv4地址: 4 172.18.19.1 [root@wen-7 shangkelianxi]# cat sh04.sh #!/bin/bash num=`netstat -nt| tr -s " " ':'|cut -d: -f6| grep [0-9]| uniq -c| sort -n ` echo -e "顯示正連接本主機的每個遠程主機的連接數和IPv4地址:\n $num"
5、寫一個腳本/root/bin/sumid.sh,計算/etc/passwd文件中的第10個用戶和第20用戶的ID之和
[root@wen-7 shangkelianxi]# cat sh05.sh #!/bin/bash clear dir=/etc/passwd n=10 m=20 id_10=`cat $dir| head -$n| tail -1|cut -d: -f3` id_20=`cat $dir| head -$m| tail -1|cut -d: -f3` #num=$((${id_10}+${id_20})) num=$[id_10+id_20] echo " $dir文件中的第$n個用戶和第$m用戶的ID之和:$num" [root@wen-7 shangkelianxi]# bash sh05.sh /etc/passwd文件中的第10個用戶和第20用戶的ID之和:184
6、寫一個腳本/root/bin/sumspace.sh,傳遞兩個文件路徑作為參數給腳本,計算這兩個文件中所有空白行之和
[root@wen-7 shangkelianxi]# bash sh06.sh /etc/rc.d/init.d/functions 兩個文件的所有空白行之和為70 [root@wen-7 shangkelianxi]# cat sh06.sh #!/bin/bash sum=0 while [ $# -gt 0 ] do num=`cat $1| grep "^[[:space:]]*$" | wc -l` sum=$(($sum+$num)) shift done echo "兩個文件的所有空白行之和為$sum " unset sum
7、寫一個腳本/root/bin/sumfile.sh,統計/etc, /var, /usr目錄中共有多少個一級子目錄和文件
[root@wen-7 shangkelianxi]# cat sh07.sh #!/bin/bash dir=0 file=0 name="/etc/ /var /usr" for line in $name do dirie=`ls -p $line| grep "/$"| wc -l` dir=$(($dir+$dirie)) fileie=`ls -p $line| grep -v "/$"| wc -l` file=$(($file+$fileie)) done echo "$name 一共為目錄為$dir個,文件為$file個" [root@wen-7 shangkelianxi]# bash sh07.sh /etc/ /var /usr 一共為目錄為179個,文件為175個
8、寫一個腳本/root/bin/argsnum.sh,接受一個文件路徑作為參數;如果參數個數小于1,則提示用戶“至少應該給一個參數”,并立即退出;如果參數個數不小于1,則顯示第一個參數所指向的文件中的空白行數
[root@wen-7 shangkelianxi]# bash sh08.sh 至少應該給一個參數: [root@wen-7 shangkelianxi]# bash sh08.sh /etc/passwd the file /etc/passwd has space list is:0 [root@wen-7 shangkelianxi]# bash sh08.sh /etc/grub2.cfg the file /etc/grub2.cfg has space list is:17 [root@wen-7 shangkelianxi]# cat sh08.sh #!/bin/bash clear [ $# -lt 1 ] && echo " 至少應該給一個參數:" || echo "the file $1 has space list is:`cat $1| grep "^$"| wc -l`"
9、寫一個腳本/root/bin/hostping.sh,接受一個主機的IPv4地址做為參數,測試是否可連通。如果能ping通,則提示用戶“該IP地址可訪問”;如果不可ping通,則提示用戶“該IP地址不可訪問”
[root@wen-7 shangkelianxi]# cat sh09.sh #!/bin/bash ping -c1 -w1 $1 &>/dev/null [ $? -eq 0 ] && echo "this ip is ok login" || echo "ERROR: this ip is no login" [root@wen-7 shangkelianxi]# bash sh09.sh 172.18.19.219 this ip is ok login [root@wen-7 shangkelianxi]# bash sh09.sh 172.18.19.210 ERROR: this ip is no login
10、chmod -rw /tmp/file1,編寫腳本/root/bin/per.sh,判斷當前用戶對/tmp/fiile1文件是否不可讀且不可寫
[wen@wen-7 ~]$ bash sh10.sh the file is no read and no write for one user [wen@wen-7 ~]$ ll /tmp/file1 ---------- 1 root root 0 8月 12 09:53 /tmp/file1 [wen@wen-7 ~]$ bash sh10.sh the file is read and write for one user [wen@wen-7 ~]$ cat sh10.sh #!/bin/bash FileName=/tmp/file1 [ ! -e $FileName ] && echo "file $FileName is no exits" && exit 2 #chmod -rw $FileName &>/dev/null if [ -r $FileName -a -w $FileName ];then echo "the file is read and write for one user" else echo "the file is no read and no write for one user" fi
11、編寫腳本/root/bin/nologin.sh和login.sh,實現禁止和充許普通用戶登錄系統。
#!/bin/bash file=/etc/nologin while true do clear echo -e "\033[31m" cat << EOF ######################## (y|Y):DOWN user login # (n|N):UP user logion # (q): exit shell # ######################## EOF echo -e "\033[0m" read -p " 是否對普通用戶登錄進行操作(參考列表輸入):" input case $input in y|Y) [ -f /etc/nologin ] && echo "user disable login already" || touch /etc/nologin; echo "user disable no login " exit 2 ;; n|N) [ -f /etc/nologin ] && rm -f /etc/nologin;echo "user enable login" || echo "user disable login already " exit 3 ;; q) exit ;; esac done
12、寫一個腳本/root/bin/hostping.sh,接受一個主機的IPv4地址做為參數,先判斷是否合格IP,否,提示IP格式不合法并退出,是,測試是否可連通。如果能ping通,則提示用戶“該IP地址可訪問”;如果不可ping通,則提示用戶“該IP地址不可訪問”
[root@wen-7 shangkelianxi]# bash ping2.sh enter a ipv4 dir :172.18.19.219 this ip is ok login [root@wen-7 shangkelianxi]# bash ping2.sh enter a ipv4 dir :172.18.19.210 ERROR: this ip is no login [root@wen-7 shangkelianxi]# bash ping2.sh enter a ipv4 dir :123.12312.3 the ipv4 dir is no ok [root@wen-7 shangkelianxi]# cat ping2.sh #!/bin/bash read -p "enter a ipv4 dir :" input echo $input|egrep "\<(([0-9]|[1-9][0-9]|1[0-9][0-9]|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])\>"&>/dev/null ##匹配輸入的ipv4地址是否合格 if [ $? -gt 0 ] ;then echo "the ipv4 dir is no ok" exit 2 else ping -c1 -w1 $input &>/dev/null [ $? -eq 0 ] && echo "this ip is ok login" || echo "ERROR: this ip is no login" fi
13、計算1+2+3+…+100的值
[root@wen-7 shangkelianxi]# bash numsum.sh 1..100的和為5050 [root@wen-7 shangkelianxi]# cat numsum.sh #!/bin/bash sum=0 num=`seq 1 100` for i in $num do sum=$[$sum+$i] done echo "1..100的和為$sum"
14、計算從腳本第一參數A開始,到第二個參數B的所有數字的總和,判斷B是否大于A,否提示錯誤并退出,是則計算之
[root@wen-7 shangkelianxi]# bash wei.sh 10 5 10,5 5小于10,不符合規定 請重新輸出參數 [root@wen-7 shangkelianxi]# bash wei.sh 5 10 5,10 參數1與參數2之和為45 [root@wen-7 shangkelianxi]# cat wei.sh #!/bin/bash sum=0 echo "$1,$2" [ $# -eq 0 ] && echo "enter at least one parameter :" && exit 2 if [ $1 -lt $2 ];then for i in `seq $1 $2` do sum=$[$sum+$i] done echo "參數1與參數2之和為$sum" else echo " $2小于$1,不符合規定" echo " 請重新輸出參數" exit 4 fi
15.當某磁盤的使用率大于80的時候,則自動報警
[root@wen-7 shangkelianxi]# bash checkdisk.sh disk /dev/sda1 is wall [root@wen-7 shangkelianxi]# cat checkdisk.sh #!/bin/bash num=`df -h| tr -s " " | cut -d" " -f1,5| sort -t' ' -k2 | grep " [0-9]\+"|tail -n1|cut -d" " -f1` num1=`df| grep "/dev/sd"|sed -r 's@.* ([0-9]+)%.*@\1@'| sort| tail -1` [ "$num1" -ge "80" ] && echo "ERROR: wall disk$num will be full!!!" || echo " disk $num is wall"
原創文章,作者:wencx,如若轉載,請注明出處:http://www.www58058.com/33812
總結的很好,很詳細,題目盡量不要帶練習,作業什么的,只要給出自己寫的內容就行了。