shell腳本

Shell腳本

Shell的簡介:
Shell是一個命令解釋器,它在操作系統的最外層,負責直接與用戶對話,把用戶的輸入解釋給操作系統,並處理各種各樣的操作系統的輸出結果,輸出到屏幕上返回給用戶,這種對話方式可以是交互式的也可以是非交互式的。
Shell腳本在運維工作中的作用地位
Shell腳本很擅長處理純文本類型的數據,而Linux中幾乎所有的配置文件、日誌文件(如:NFS、rsync、httpd、Nginx、lvs等)都是純文本類型的文件。因此,如果學好shell腳本語言,就可以利用他在Linux系統中發揮巨大作用。
Shell腳本語言的種類
在UNIX和LINUX中主要有兩大類shell
1)Bourne shell(包括sh,ksh,bash)
Bourne shell (sh)
Kor n shell (ksh)
Bourne Again shell (bash)
POSIX shell (sh)
2)C shell(包括csh,tcsh)
C shell (csh)
TENEX/TOPS Cshell (tcsh)
Shell腳本語言是弱類型語言,較爲通用的shell有標準的Bourne shell(sh)和C shell (csh)。其中Bourne shell(sh)已經被bash shell取代。
查看系統的SHELL:
[root@xuexi ~]# cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/bin/dash
/bin/tcsh
/bin/csh
其他運維人員常用的腳本語言種類:
1) PHP
PHP是網頁程序,也是腳本語言。更專注於web頁面的開發,列如:dedecms,discus.也可以處理系統日誌,配置文件等。
2) Perl
Perl腳本語言比shell強大的多,2010前很火,語法靈活、複雜,實現方式很多,不易讀,團隊協作困難。
3)Python
近幾年很火,可以做腳本開發,也可以實現web開發。中等以上企業都要求會Python。
Shell與PHP、Perl、Python語言的區別和優勢:
Shell的優勢在於處理操作系統底層的業務,因爲有大量的命令爲它做支持,2000多個命令都是shell編程的有力支持,特別是grep,awk,sed等;例如:一鍵軟件安裝、優化,監控報警腳本,常規的業務應用,shell開發更簡單便捷,符合運維的大原則。
PHP、Python優勢在於開發運維工具,web界面的管理工具,以及web業務的開發等。
常見操作系統默認shell
Linux是Bourne Again shell (bash)
Solaris和FreeBSD是Bourne shell (sh)
AIX下是Korn shell (ksh)
HP-UX是POSIX shell (sh)
Shell腳本的建立和執行:
1) 腳本的開頭
一個規範的shell腳本的第一行會指出由哪個程序(解釋器)來執行腳本中的內容,在Linux bash編程中爲:
#!/bin/bash或#!/bin/sh
其中開頭的“#!”又稱爲幻數,在執行bash腳本的時候,內核會根據“#!”後的解釋器來確定該有哪個程序解釋腳本中的內容。注:這一行必須在每個腳本頂端的第一行,如果不是第一行則是註釋。
2) Sh和bash的區別:
Sh是bash的一個軟連接,標準寫法是#!/bin/bash,但實際上都一樣。
[root@xuexi ~]# ll /bin/sh
lrwxrwxrwx. 1 root root 4 Aug 31 06:13 /bin/sh -> bash
[root@xuexi bin]# bash --version
bash –version(bash的版本信息。)
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html&gt;

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
printf "\033]0;%s@%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"
3) 腳本註釋:
在Linux中#後面的是註釋,加註釋既是方便自己也是方便別人,特別是關鍵位置,加上註釋便於閱讀腳本。
Shell腳本的執行:
當shell腳本以非交互式(文件方式)運行時,它會先查看環境變量ENV,該變量指定了一個環境文件(通常是.bashrc,.bash_profile,/etc/profile,/etc/bashrc等)然後從該環境變量文件開始執行,當讀取ENV文件後,shell纔開始執行shell腳本中的內容。
Crond定時任務需要將系統的環境變量重新定義。
Shell腳本的執行通常採用以下的三種方式:
1) bash 腳本名 或 sh 腳本名
2) 全路徑/腳本名 或 ./腳本名(相對路徑在當前路徑下,注:用這種方法文件必須有可執行權限。)
3) Source 腳本名 或 . 腳本名 #注意“.”點號(注;這種方法運行腳本,腳本中的環境變量會影響到系統的環境變量)。
Shell腳本開發基本規範及習慣:
1) 開頭指定腳本解釋器。
2) 開頭加版本版權等信息。
3) 腳本中不用中文註釋
4) 腳本以.sh爲擴展名
5) 代碼書寫優秀習慣。
1) 成對的符號內容要一次寫出來,防止遺漏。如:”” ‘’ [] {}等
2) {}中括號裏兩端有空格,書寫時可先預留出來再寫內容。
3) 流程控制語句一次書寫完,在添加內容,如:
If語句格式:
If 條件內容
Then
內容
fi
for循環一次寫完
for
do
done
4) 通過縮進讓代碼易讀。
環境變量:
環境變量用於定義shell的運行環境,保證shell命令的正確執行,shell通過環境變量來確定登錄用戶名、命令路徑、終端類型、登陸目錄等,所有的環境變量都是系統全局變量,可用於子進程中,這包括編輯器。Shell腳本和各種應用(定時任務特殊需重新定義)。
環境變量可以在命令行中定義,但用戶退出時這些變量值也會丟失,因此最好在用戶的家目錄下的.bash_profile文件中或全局變量/etc/profile,/etc/bashrc文件或者/etc/profile.d/中定義。這樣每次用戶登錄時這些變量值都會被初始化。
傳統上,所有的環境變量均爲大寫。環境變量應用於用戶進程前,必須用export命令導出。
環境變量可用在創建他們的shell和從該shell派生的任意子shell或進程中,他們通常被稱爲全局變量以區別局部變量。
用env可以查看系統定義的環境變量
設置全局環境變量:(命令行定義,用戶退出或重啓系統則不再生效)
1) export 變量名=value
2) 變量名=value; export 變量名
3) Declare -x 變量名=value
永久生效應將上述內容添加到環境變量的配置文件中。
顯示和取消變量:
1)用echo 或 printf $變量名(printf意思:format and print data
[root@xuexi ~]# echo $USER
root
[root@xuexi ~]# printf "$USER\n"(\n換行的意思)
root
2)用env(printenv)或set顯示默認的環境變量。
[root@xuexi ~]# env
HOSTNAME=xuexi
SELINUX_ROLE_REQUESTED=
TERM=xterm
SHELL=/bin/bash
HISTSIZE=1000
SSH_CLIENT=192.168.0.18 63285 22
SELINUX_USE_CURRENT_RANGE=
SSH_TTY=/dev/pts/0
USER=root
3)用unset 變量名 取消變量值
局部變量:
定義本地變量:
本地變量在用戶當前的shell的腳本中使用,例如,本地變量OLDBOY取值爲ett098,這個值只在用戶當前shell生存期中有意義。如果在shell中啓動另一個進程或退出,本地變量OLDBOY值將無效。
1)普通字符串變量定義:
變量名=value
變量名=’value’
變量名=”value”
Shell中變量名的要求:一般是字母,數字,下劃線組成。字母開頭。
[root@xuexi ~]# a=192.168.1.1
[root@xuexi ~]# b='192.168.1.1'
[root@xuexi ~]# c="192.168.1.1"
[root@xuexi ~]# echo "a=$a"
a=192.168.1.1
[root@xuexi ~]# echo "b=$b"
b=192.168.1.1
[root@xuexi ~]# echo "c=${c}"
c=192.168.1.1
小結:連續普通字符串內容,賦值給變量,內容是什麼,變量打印就輸出什麼。
[root@xuexi ~]# a=192.168.1.1-$a
[root@xuexi ~]# b='192.168.1.1-$a'
[root@xuexi ~]# c="192.168.1.1-$a"
[root@xuexi ~]# echo "a=$a"
a=192.168.1.1-192.168.1.1
[root@xuexi ~]# echo "b=$b"
b=192.168.1.1-$a
[root@xuexi ~]# echo "c=${c}"
c=192.168.1.1-192.168.1.1-192.168.1.1
上述實例中,第一種a變量的方式是直接定義變量內容,內容一般爲簡單連續的數字、字符串、路徑名等。
第二種b變量的方式是通過單引號定義變量,這個方式的特點是:輸出變量時引號是什麼就輸出什麼,即使內容中包含變量也會把變量名原樣輸出,此法適合定義顯示純字符串。
第三種c變量方式是通過雙引號定義變量。這個方式的特點:輸出變量時雙引號裏的變量會經過解析後輸出該變量內容,而不是把引號中變量名原樣輸出,適合於字符串中附帶有變量的內容的定義。
筆者習慣:數字不加引號,其他默認加雙引號。
Grep過濾實例:
[root@xuexi ~]# vim a.txt
[root@xuexi ~]# O=testchars
[root@xuexi ~]# grep $O a.txt
testchars
[root@xuexi ~]# grep '$O' a.txt
[root@xuexi ~]# grep "$O" a.txt
testchars
awk過濾實例:
[root@xuexi ~]# ETT=123
[root@xuexi ~]# awk 'BEGIN {print "$ETT"}'
$ETT
[root@xuexi ~]# awk 'BEGIN {print '$ETT'}'
123
[root@xuexi ~]# awk 'BEGIN {print $ETT}'

[root@xuexi ~]# ETT='abc'(雙引號一樣)
[root@xuexi ~]# awk 'BEGIN {print '$ETT'}'

[root@xuexi ~]# awk 'BEGIN {print $ETT}'

[root@xuexi ~]# awk 'BEGIN {print "$ETT"}'
$ETT
[root@xuexi ~]# awk 'BEGIN {print "'$ETT'"}'
abc
[root@xuexi ~]# awk 'BEGIN {print '"$ETT"'}'

[root@xuexi ~]#
Sed過濾實例:
[root@xuexi ~]# vim a.txt
[root@xuexi ~]# sed -n '/$USER/p' a.txt
[root@xuexi ~]# sed -n "/$USER/p" a.txt
root
[root@xuexi ~]# sed -n /$USER/p a.txt
root
自定義普通字符串變量的建議:
1) 內容是純數字(沒空格),定義方式可以不加引號(單或雙),例如:
O=123
M=yes
2) 沒特殊情況,字符串一般用雙引號定義,特別是多個字符串中間有空格時,例如:
U=“This is pen”
Y=” my god”
3) 變量內容需要原樣輸出時,用(‘’)單引號
P=’U’
變量的命名規範:
1)變量命名要統一,使用全部大寫字母,如APACHE_ERRNUM;語義要清晰,能夠正確表達變量內容的含義,過長的英文單詞可採用前幾個字符代替,多個單詞連接使用“”號連接,引用時,做好以${APACHE_ERR_NUM }加大括號或“${APACHE_ERR_NUM }”外面加雙引號方式引用變量;
2)避免無含義字符或數字
小結:定義變量多模仿系統的定義,規範的定義寫法:
1) OLDBOYAge=1
2) oldboy_age=1
3) oldboyAgeSex=1(駝峯語法)
把命令作爲變量定義方法:實例:
[root@xuexi ~]# CMD=$(date +%F)
[root@xuexi ~]# echo $CMD
2018-01-08
[root@xuexi ~]# CMD=date +%F
[root@xuexi ~]# echo $CMDbr/>2018-01-08
Shell特殊變量
1.位置變量:
$0獲取當前執行的shell腳本的文件名,包括腳本路徑。
$n獲取當前執行的shell腳本的第n個參數值,n=1…9,當n爲0時表示腳本的文件名,如果n大於9用大括號括起來${10}.
$#獲取當前執行的shell腳本後面傳參的參數的總個數。
$?獲取執行上一個指令的返回值(0爲成功,非0爲失敗)這個很有用。
$?返回值:0爲成功,2爲權限被拒,1~125表示運行失敗,腳本命令,系統命令錯誤或參數傳遞錯誤,126是找到該命令,但無法執行,127表示找不到命令,>128表示命令被系統強制結束。
$*獲取當前shell的所有參數,將所有的命令行參數視爲單個字符串,相當於“$1$2$3….”注意與$#的區別。
$@這個程序的所有參數“$1””$2””$3”......,這是講參數傳遞給其他程序的最佳方式,因爲他會保留所有內嵌在每個參數裏的任何空白。
$$獲取當前shell的進程號(PID).
$!執行上一個指令的PID。
$_在此之前執行的命令或腳本的最後一個參數。
$0實例:
[root@xuexi ~]# cat d.sh
echo $0
[root@xuexi ~]# sh d.sh
d.sh
[root@xuexi ~]# cat d.sh
dirname $0
basename $0
[root@xuexi ~]# sh pwd/d.sh
/root
d.sh
$n實例:
[root@xuexi ~]# cat d.sh
$1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15
[root@xuexi ~]# sh d.sh {a..z}
a b c d e f g h i j k l m n o
$#實例:
[root@xuexi ~]# cat d.sh
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11} ${12} ${13} ${14} ${15}
echo $#
[root@xuexi ~]# sh d.sh {a..z}
a b c d e f g h i j k l m n o
26
[root@xuexi ~]# cat d.sh
[ $# -ne 2 ] && {
echo "muse two"
exit 1(1相當於賦值給$?)
}
echo "ok"
[root@xuexi ~]# sh d.sh qq
muse two
[root@xuexi ~]# sh d.sh qq uuu
ok
注:在腳本調用,一般用exit 0,函數retrun 0.控制命令及腳本的返回值
http://oldboy.blog.51cto.com/2561410/1175971 (linux下set和eval的使用案例)
${value:-word}:如果value未定義,則變量值爲word
${value:?”not defined”}:如果變量value爲賦值,則會顯示-bash:value: not defined
If條件句:
單分支結構:
語法:
If[條件]
Then
指令
fi

If[條件]
指令
fi
實例:
[root@xuexi ~]# cat if.sh
#!/bin/bash
file="a.txt"
dir="/server/scripts"
#no1
if [ ! -d $dir ]
then
mkdir -p $dir
fi
#no2
if [ ! -f $file ]
then
touch $dir/$file
fi
ls -l $dir/$file
[root@xuexi ~]# sh if.sh
-rw-r--r--. 1 root root 43 Dec 7 19:11 /server/scripts/a.txt
內存小於100M發郵件報警實例:
[root@xuexi ~]# cat cache.sh
#!/bin/bash
cache=free -m|awk 'NR==3 {print $NF}'
if [ $cache -lt 900 ]
then
echo "cache <900"|mail -s "cache" root
fi
多分支結構:
If 條件
Then
指令
elif 條件
then
指令
else
指令
if
實例:
[root@xuexi ~]# cat bijiao.sh
#!/bin/bash
expr $1 + 0 &>/dev/null
value=$?
expr $2 + 0 &>/dev/null
value1=$?
if [ $value -ne 0 -o $value1 -ne 0 ]
then
echo "Please re-enter"
exit 1
fi
if [ $1 -eq $2 ]
then
echo "$1 = $2"
elif [ $1 -lt $2 ]
then
echo "$1 < $2"
else
echo "$1 > $2"
fi
exit 0
檢測MySQL啓動是否正常,啓動了給個提示,沒啓動就用腳本啓動實例:
[root@xuexi ~]# cat listen.sh
#!/bin/bash
Port=lsof -i :3306|grep mysql|wc -l
if [ $Port -eq 1 ]
then
echo "MySQL is running"
else
/etc/init.d/mysqld start
fi
遠程:http://oldboy.blog.51cto.com/2561410/942530
WEB服務監控:
[root@xuexi ~]# cat web.sh
#!/bin/bash
Port=lsof -i :80|grep httpd|wc -l
if [ $Port -ne 6 ]
then
/etc/init.d/httpd start
else
echo "Httpd is running"
fi
方法2:
[root@xuexi ~]# cat web1.sh
#!/bin/bash
value=curl -I 127.0.0.1|awk 'NR==1'|awk '{print $(NF-1)}' &>/dev/null
if [ $value -ne 200 ]
then
/tec/init.d/httpd start
else
echo "Httpd is running"
fi
web服務判斷條件:
[root@xuexi ~]# lsof -i :80|wc -l(判斷條件大於1即可)
7
[root@xuexi ~]# nmap 192.168.0.40 -p 80|grep open|wc -l(判斷條件等於1即可)
1
[root@xuexi ~]# ps -ef|grep httpd|wc -l(判斷條件大於2即可)
7
[root@xuexi ~]# curl -I -s 192.168.0.40|head -1|awk '{print $2}'(判斷條件等於200即可)
200
[root@xuexi ~]# wget --spider --timeout=3 --tries=2 192.168.0.40 &>/dev/null
[root@xuexi ~]# echo $?(判斷條件等於0即可)
0
測試語句:
【語法說明】:
格式一:test<測試表達式>
格式二:[<測試表達式>]
格式三:[[<測試表達式>]]
說明
格式一和格式二是等價的

格式一實例:(可以man test瞭解詳情)
[root@xuexi ~]# test -f file && echo "1" || echo 0
0
[root@xuexi ~]# test -f a.log && echo "1" || echo 0
1
加上!是非的意思;取反:
[root@xuexi ~]# test ! -f a.log && echo "1" || echo 0
0
[root@xuexi ~]# test ! -f file && echo "1" || echo 0
1
格式二實例:
[root@xuexi ~]# [ ! -f file ] && echo "1" || echo 0
1
[root@xuexi ~]# [ -f file ] && echo "1" || echo 0
0
[root@xuexi ~]# [ -f a.log ] && echo "1" || echo 0
1
[root@xuexi ~]# [ ! -f a.log ] && echo "1" || echo 0
0
格式三:實例:
[root@xuexi ~]# [[ ! -f a.log ]] && echo "1" || echo 0
0
[root@xuexi ~]# [[ -f a.log ]] && echo "1" || echo 0
1
[root@xuexi ~]# [[ -f file ]] && echo "1" || echo 0
0
[root@xuexi ~]# [[ ! -f file ]] && echo "1" || echo 0
1
文件測試操作符:
常用文件測試操作符:
-f 文件 file 若文件存在且爲普通文件則真。
-d 文件 directory 若文件存在且爲目錄文件則真。
-s 文件 size 若文件存在且不爲空(文件大小非0)則真。
-e 文件 exist 若文件存在並且是普通文件則真,要區別-f
-r 文件 read 若文件存在且可讀則真
-w 文件 write 若文件存在且可寫則真
-x 文件 excute 若文件存在且可執行則真
-L 文件 link 若文件存在且爲鏈接文件則真
f1 -nt f2 newer than 若文件f1比文件f2新則真
f1 -ot f2 older than 若文件f1比文件f2舊則真
字符串測試操作符:
字符串測試操作符的作用:比較兩個字符串是否相同、字符串長度是否爲零,字符串是否被爲NULL(注:bash區分零長度字符串和空字符串)等。
“=”比較兩個字符串是否相同,與==等價,如if [ “$a”=”$b” ],其中$a這樣的變量最好用””號括起來,因爲如果中間有空格,*等符號就可能出錯了,當然更好的方法是[ “${a}”=”${b}” ].“!=”取反的意思。
常用字符串測試操作符:
-z“字符串” 若串長度爲0則真,-z可以理解爲zero
-n“字符串” 若串長度不爲0則真,-z可以理解爲no zero
“串1”=“串2” 若字符串1等於字符串2則真,可用“==”代替“=”
“串1”!=“串2” 若字符串1不等於字符串2則真,不可用“!==”代替“!=”
字符串測試操作提示符提示:
1)-n比較字符串長度是否不爲零,如果不爲零則爲真,如:[ -n “$myvar” ]
2) -z比較字符串是否等於零,如果等於零則爲真,如:[ -z “$myvar” ]
特別注意,對於以上表格中的字符串測試操作符號,如:[ -n “$myvar” ],要把字符串用“”引起來。
4) 字符串比較,比較符號兩端最好都有空格,多參考系統腳本。
[root@xuexi ~]# sed -n '30,31p' /etc/init.d/network

Check that networking is up.

[ "${NETWORKING}" = "no" ] && exit 6
整數二元比較操作符:
在[]中使用的比較符 在(())和[[]]中使用的比較符 說明
-eq = equal的縮寫,相等
-ne != not equal的縮寫,不相等
-gt > 大於 greater than
-ge >= 大於等於greater equal
-lt < 小於類似less than
-le <= 小於等於less equal
邏輯操作符:
在[]中使用的邏輯操作符 在[[]]中使用的邏輯操作符 說明
-a && and 與,兩端都爲真,則真
-o || or 或,兩端有一個爲真則真
! ! not 非,相反則爲真。
監控web服務器是否正常:

  1. 端口:
    本地:ss,netstat,lsof
    遠程:telnet,nmap,nc
  2. 本地進程數:
  3. Header(http code)curl -I 返回值200就OK.
  4. URL(wget,curl),模擬用戶的方式。
  5. PHP,Java寫監控的程序,模擬用戶的方式
    最常用是端口和URL或監控程序的結合。
    Apache的啓動腳本(簡單的)
    [root@xuexi ~]# cat start_apache.sh
    #!/bin/bash
    . /etc/init.d/functions
    a=$1
    b=$2
    apache=/etc/init.d/httpd
    if [ -n "$b" ]
    then
    echo "USAGE:$0 {start|stop|restart}"
    exit 1
    fi
    if [ "$a" = "start" ]
    then
    then
    $apache $a &>/dev/null
    action "starting apache" /bin/true
    elif [ "$a" = "stop" ]
    then
    $apache $a &>/dev/null
    action "stopping apache" /bin/true
    elif [ "$a" = "restart" ]
    then
    $apache graceful &>/dev/null
    action "restarting nginx" /bin/true
    else
    echo "USAGE:$0 {start|stop|restart}"
    fi
    exit 0

Shell函數:
函數的作用:簡單的說函數的作用就是把程序裏多次調用的相同的代碼的部分,定義成一份,然後起個名字,所有的調用都只用這個名字就可以了,修改代碼時,只需要改變函數體內的泰馬即可。
優勢:
1) 把相同的程序段定義成函數,可以較少程序代碼量。
2) 增加程序的可讀,易讀性。
3) 實現程序的功能模塊化。
Shell函數語法:
語法格式:
簡單的語法:
函數名(){
指令…
Return n
}
規範的語法:
Function 函數名(){
指令…..
Return n
}
Shell的執行方法:
1) 直接執行函數名:
函數名
注意:
a. 執行函數時,不要帶小括號。
b. 函數定義及函數體必須在要執行的函數名前面定義,shell的執行從上到下按行執行的。
2) 帶參數的函數執行方法:
函數名 參數1 參數2
函數帶參數的說明:
1) 在函數體中位置變量($1,$2,$3,$#,$*,$?以及$@)都可以是函數的參數。
2) 父腳本的參數則臨時地被函數參數所掩蓋或隱藏。
3) $)比較特殊,它仍是父腳本的名稱。
4) 當函數完成時,原來的命令行參數會恢復。
5) 在shell函數裏面,return命令的功能與工作方式與exit相同,用於跳出函數。
6) 在shell函數裏使用exit會終止整個shell腳本。
7) Return語句會返回一個退出值給調用的程序。
Mysql啓動腳本實例:
[root@xuexi ~]# cat startmysql.sh
#!/bin/bash
function mysql(){
/bin/sh /application/mysql/bin/mysqld_safe
}
function stopmysql1(){
/application/mysql/bin/mysqladmin -u root shutdown &>/dev/null
if [ $? -eq 0 ]
then
action "stopping mysql" /bin/true
else
action "stopping mysql" /bin/false
fi
}
. /etc/init.d/functions
if [ "$1" = "start" ]
then
mysql &>/dev/null &
if [ $? -eq 0 ]
then
action "starting mysql" /bin/true
else
action "starting mysql" /bin/false
fi
elif [ "$1" = "stop" ]
then
stopmysql1
elif [ "$1" = "restart" ]
then
stopmysql1 &>/dev/null
if [ $? -eq 0 ]
then
action "stopping mysql" /bin/true
else
action "stopping mysql" /bin/false
fi
mysql &>/dev/null &
if [ $? -eq 0 ]
then
action "starting mysql" /bin/true
else
action "starting mysql" /bin/false
fi
else
echo "usage:{start|restart|stop}"
fi
當型循環和直到型循環:

  1. while條件句語法:
    while 條件
    do
    指令…
    Done
  2. until 條件句語法:(使用不多,瞭解,直到循環)
    until 條件
    do
    指令…
    done
    防止腳本執行中斷的方法:
    1) 執行腳本 &(後臺運行腳本)
    2) Screen命令
    3) Nohup 腳本路徑/腳本名 &
    進程管理命令:
    Bg:後臺運行 fg:掛起程序 jobs:顯示後臺程序 kill/killall/pkill:殺死進程 crontab:設置定時 ps:查看進程 pstree:顯示進程狀態樹 top:顯示進程(動態) nice:改變優先權 nohup:用戶退出系統之後繼續工作 pgrep:查找匹配條件的進程 strace:跟蹤一個進程的系統調用情況 ltrace:跟蹤程序調用庫函數的情況 vmstat:報告虛擬內存統計信息
    While循環實例:計算100內之和:
    [root@xuexi ~]# cat while1.sh
    #!/bin/bash
    i=1
    sum=0
    while [ $i -le 100 ]
    do
    sum=$(expr $sum + $i)
    let i++
    done
    echo "$sum"
    while循環小結:
    1) while循環的特長是執行守護進程以及我們希望循環不退出持續執行,用於頻率小於1分鐘循環處理(crond),其他的while循環幾乎都可以被我們即將要講for循環代替。
    2) case語句可以替換if語句,一般在系統啓動腳本傳入少量固定規則字符串,用case,其他判斷多用if.
    3) 一句話,if,for語句最常用,其次while(守護進程),case(服務啓動腳本)。
    For循環結構:
    1.for循環結構語法:
    For 變量名 in 變量取值列表
    Do
    指令
    done
    2.C語言型for循環結構語法:
    For((exo1;exp2;exp3))
    do
    指令
    done
    用for循環實現將文件名中的oldboy全部改成linux,並且擴展名改成大寫,for循環的循環體不能出現oldboy字樣。實例:
    [root@xuexi ~]# ls /oldboy/
    oldboy_10.html oldboy_2.html oldboy_4.html oldboy_6.html oldboy_8.html
    oldboy_1.html oldboy_3.html oldboy_5.html oldboy_7.html oldboy_9.html
    [root@xuexi ~]# vim for2.sh
    [root@xuexi ~]# sh for2.sh
    [root@xuexi ~]# ls /oldboy/
    linux_10.HTML linux_2.HTML linux_4.HTML linux_6.HTML linux_8.HTML
    linux_1.HTML linux_3.HTML linux_5.HTML linux_7.HTML linux_9.HTML
    [root@xuexi ~]# cat for2.sh
    #!/bin/bash
    cd /oldboy/
    for i in ls
    do
    mv $i $(echo $i|sed 's#oldboy(.)html#linux\1HTML#g')
    done
    批量創建10個系統賬戶並設置密碼(密碼不態相同。)
    [root@xuexi ~]# cat for.sh
    #!/bin/bash
    for i in seq -w 10
    do
    useradd oldboy$i&&\
    echo "root$i"|passwd --stdin oldboy$i
    done
    批量創建10個系統賬戶並設置密碼(密碼不態相同且是隨機數。)
    [root@xuexi ~]# cat for.sh
    #!/bin/bash
    . /etc/init.d/functions
    for i in seq -w 10
    do
    passwd=$(echo "$RANDOM"|md5sum|cut -c 1-8)
    useradd oldboy$i&&\
    echo "passwd"|passwd --stdin oldboy$i &>/dev/null &&\
    action "chenggong" /bin/true
    echo -e "oldboy$i\t $passwd" >>/oldboy/a.txt
    done
    break continue exit對比;
    命令 說明
    Break n n 表示跳出循環的層數,如果省略n表示跳出整個循環。
    Continue n n表示退出到第n層繼續循環,如果省略n表示跳過本次循環,忽略本次循環剩餘代碼,進入循環的下一次循環。
    Exit n 退出當前shell程序,n表示返回值,n也可以省略,再下一個shell裏通過$?接收這個n值。
    Return n 用於在函數裏,作爲函數的返回值,用於判斷函數執行是否正確。
    Shell數組介紹
    平時的定義a=1,b=2,c=3,變量如果多了,再一個一個定義很費勁,並且取變量的也費勁。
    簡單的說,數組就是相同數據類型的元素按一定順序排列的集合。
    數組就是把有限類型相同的變量用一個名字命名,然後用編號區分他們的變量的集合,這個名字成爲數組名,編號成爲數組下標。組成數組的各個變量成爲數組的分量,也稱爲數組的元素,有時也稱爲下標變量。
    數組的定義與增刪改查:
    格式1:
    Array=(value1 value2 value3)
    1) 數組的定義
    [root@xuexi ~]# array=(1 2 3)
    2) 獲取數組的長度
    [root@xuexi ~]# echo ${#array[@]}
    3
    [root@xuexi ~]# echo ${#array[
    ]}
    3
    3) 打印數組的元素
    [root@xuexi ~]# echo ${array[0]}
    1
    [root@xuexi ~]# echo ${array[1]}
    2
    [root@xuexi ~]# echo ${array[2]}
    3
    用for循環打印出字符數小於6的單詞實例:
    I am oldboy teacher welcome to oldboy training class
    方法1:
    [root@xuexi ~]# sh for4.sh
    I
    am
    to
    class
    [root@xuexi ~]# cat for4.sh
    #!/bin/bash
    array=(I am oldboy teacher welcome to oldboy training class)
    for i in $(echo ${array[@]})
    do
    if [ ${#i} -lt 6 ]
    then
    echo "$i"
    fi
    done
    方法2:
    [root@xuexi ~]# sh for4.sh
    I
    am
    to
    class
    [root@xuexi ~]# cat for4.sh
    #!/bin/bash
    for i in I am oldboy teacher welcome to oldboy training class
    do
    if [ ${#i} -lt 6 ]
    then
    echo "$i"
    fi
    done
    監控web站點目錄(/var/html/www)下所有文件是否被惡意篡改(內容被改了),如果有就打印所改動的文件名(發郵件,定時任務每三分鐘執行一次。實例:)
    [root@xuexi ~]# cat file_md5.sh 創建文件對比的信息庫
    find /var/html/bbs/ -type f|xargs md5sum >/oldboy/md5sum.db
    find /var/html/bbs/ -type f >/oldboy/a.log
    [root@xuexi ~]# cat web6.sh
    #!/bin/bash
    n=$(cat /oldboy/a.log|wc -l)(源目錄文件的行數)
    while true
    do
    Md5=$(md5sum -c /oldboy/md5sum.db 2>>/dev/null|grep -i fail|wc -l)(md5對比錯誤的行數)
    find /var/html/bbs/ -type f >/oldboy/new-a.log(隨時查看源文件的行數)
    log=/oldboy/check.log
    if [ $Md5 -ne 0 ] || [ $(cat /oldboy/new-a.log|wc -l) -ne $n ]
    then
    echo "$(md5sum -c /oldboy/md5sum.db 2>>/dev/null|grep -i fail)" >$log
    diff /oldboy/a.log /oldboy/new-a.log >>$log
    mail -s "file is cuangai $(date)" [email protected] <$log
    fi
    sleep 3
    done
    shell腳本小結:
    1) 重視書寫習慣,開發規範和開發制度,儘量減少腳本調試的難度,提升開發效率。
    2) 基本語法要熟悉,才能利用好調試。
    3) 思路要清晰,複雜的腳本要簡單化分段實現。
    Shell腳本調試技巧:
    1.使用dos2unix命令處理來自windows下開發的腳本。
    第一步.沒有安裝先安裝yum install -y dos2unix
    第二步[root@xuexi ~]# cat -v mysql1.sh檢測
    第三步:[root@xuexi ~]# dos2unix mysql1.sh 用dos2unix命令格式化
    dos2unix: converting file mysql1.sh to UNIX format ...
    2 使用echo 命令調試
  3. 使用bash命令參數調試:
    -n:不會執行改腳本,進查詢腳本語法是否有問題,並給出錯v誤提示。
    -v: 在執行腳本時,先將腳本的內容輸出到屏幕上然後執行腳本,如果有錯誤,也會給出提示。
    -x : 將執行的腳本內容及輸出顯示到屏幕上,這個是調試很有用的參數
    4.set腳本調試工具:
    使用bash -x 會把整個腳本執行一遍並檢測一般,set可以分段檢測,只檢測你想檢測的那一段。
    #!/bin/bash
    set -x
    for n in {1..9}
    do
    for m in {1..9}
    do
    if [ $m -le $n ]
    then
    echo -ne "${m}x${n}=$(( $m * $n ))\t"
    fi
    set +x
    [root@xuexi ~]# sh koujue.sh
    • for n in '{1..9}'
    • for m in '{1..9}'
    • '[' 1 -le 1 ']'
    • echo -ne '1x1=1\t'
      1x1=1 + set +x
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章