模块二、shell脚本逻辑结构
七、if结构条件句知识与实践
(一)if条件句单双分支语法
1、单分支 if 条件 then 指令 fi 2、双分支 if 条件 then 指令 else 指令集2 fi
(二)if条件句多分支语句
if 条件1 then 指令1 elif 条件2 then 指令2 elif 条件3 then 指令3 else 指令4 fi
实例:
如果不存在目录/backup,则创建。 [ scripts]# cat 07-01.sh #!/bin/bash path="/backup" [ -d $path ] || mkdir $path -p if [ -d $path ] then : else mkdir $path -p fi if [ !-d $path] then mkdir $path -p fi [ scripts]# 开发shell脚本判断内存是否充足,如果小于100,提示不足,如果大于100提示充足。 [ scripts]# cat 07-02.sh #!/bin/bash mem=`free -m | awk 'NR==3{print $NF}'` if [ $mem -lt 100 ] then echo "内存不充足!" else echo "内存充足!" fi [ scripts]#
判断两个整数大小:
[ scripts]# cat 07-03.sh #!/bin/bash read -p "请输入两个整数:" a b expr $a + $b + 1 &>/dev/null if [ $? -ne 0 ] then echo "请输入两个整数。" exit 0 fi if [ -z "$b" ] then echo "请输入两个整数。" exit 1 fi if [ $a -lt $b ] then echo "$a小于$b" elif [ $a -gt $b ] then echo "$a大于$b" else echo "$a等于$b" fi [ scripts]# 如果使用传参方式: [$# -ne 2 ]判断参数是否为两个。
打印一个安装菜单:
[ scripts]# cat 07-04.sh #!/bin/bash cat <<EOF 1.install lamp 2.install lnmp 3.exit EOF read -p "请输入一个数字{1|2|3}:" n expr $n + 2 &>/dev/null if [ $? -ne 0 ] then echo "usage:$0{1|2|3}" exit 0 fi if [ $n -eq 1 ] then echo "install lamp" elif [ $n -eq 2 ] then echo "install lnmp" elif [ $n -eq 3 ] then echo "exit" else echo "usage:$0{1|2|3}" fi [ scripts]#
八、函数知识与实践
(一)shell函数语法
第一种语法 第二种语法 第三种语法
function 函数名(){ } function 函数名 {} 函数名() { }
实例
[ scripts]# cat 08-01.sh #!/bin/bash function oldboy(){ echo "i am $1 teacher" } function oldgirl { echo "i am $1 teacher" } test() { echo "this is $1" } oldboy $1 oldgirl $2 test $3 [ scripts]# bash 08-01.sh oldboy oldgirl test i am oldboy teacher i am oldgirl teacher this is test [ scripts]#
实例:检测web网站是否正常
wget 命令:
--spider 模拟爬虫
-q 安静访问
-o /dev/null 不输出
-T --timeout 超时时间
-t --tries 重试次数
wget --spider -T 5 -q -o /dev/null -t 2 www.baidu.com echo $?
curl命令:
-I 查看响应头
-s 安静的
-o /dev/null 不输出
-w%{http_code} 返回状态码
[ scripts]# curl -I -s -o /dev/null -w "%{http_code}\n" www.baidu.com 200 [ scripts]#
案例:
[ scripts]# cat 08-02.sh #!/bin/bash function usage(){ echo "usage:$0 url" exit 1 } function url_check { wget -q -o /dev/null -T 5 -t 3 $1 if [ $? -eq 0 ] then echo "$1 is ok!" else echo "$1 is fail!" fi } main(){ if [ $# -ne 1 ] then usage else url_check $1 fi } main $* [ scripts]#
九、case结构条件句应用时间
(一)case语法结构
case结构条件句相当于多分支if条件语句,但是它比这些条件句看起来更规范工整,常被用于实现系统服务脚本等应用场景中。
case语句的语法结构:
case "变量" in 值1) 指令1 ;; 值2) 指令2 ;; 值3) 指令3 ;; *) 指令4 esac
(二)实例1:
[ scripts]# cat 09-03.sh #!/bin/bash cat <<EOF 1.install lnmp 2.install lamp 3.exit EOF read -p "请输入一个数字{1|2|3}:" num expr $num + 2 &>/dev/null if [ $? -ne 0 ] then echo "usage:$0{1|2|3}" exit 1 fi case $num in 1) echo "install lnmp" ;; 2) echo "install lamp" ;; 3) echo "exit" exit ;; *) echo "usage:$0{1|2|3}" exit 1 esac [ scripts]#
(三)实例2:
当用户输入对应的数字选择水果的时候,告诉他选择的水果是什么,并给水果单词加上一种颜色(随意),要求用case语句实现。
内容的颜色用数字表示,范围为30-37,每个数字代表一种颜色。 echo -e "\033[30m 黑色字oldboy trainning \033[0m" #<==30m表示黑色字。 echo -e "\033[31m 红色字oldboy trainning \033[0m" #<==31m表示红色字。 echo -e "\033[32m 绿色字oldboy trainning \033[0m" #<==32m表示绿色字。 echo -e "\033[33m 棕色字oldboy trainning \033[0m" #<==33m表示棕色字(brown),和黄色字相近。 echo -e "\033[34m 蓝色字oldboy trainning \033[0m" #<==34m表示蓝色字。 echo -e "\033[35m 洋红字oldboy trainning \033[0m" #<==35m表示洋红色字(magenta),和紫色字相近。 echo -e "\033[36m 蓝绿色oldboy trainning \033[0m" #<==36m表示蓝绿色字(cyan),和浅蓝色字相近。 echo -e "\033[37m 白色字oldboy trainning \033[0m" #<==37m表示白色字。
基础脚本1:
[ scripts]# cat 09-04.sh #!/bin/bash cat <<EOF 1.apple 2.pear 3.banana 4.cherry EOF read -p "请输入一个数字{1|2|3|4}:" num expr $num + 2 &>/dev/null if [ $? -ne 0 ] then echo "usage:$0 {1|2|3|4}" exit 1 fi case $num in 1) echo -e "\033[31m apple \033[0m" ;; 2) echo -e "\033[32m pear \033[0m" ;; 3) echo -e "\033[33m banana \033[0m" ;; 4) echo -e "\033[34m cherry \033[0m" ;; *) echo "usage:$0 {1|2|3|4}" exit esac [ scripts]#
高级脚本2:
颜色函数: [ scripts]# cat color.sh #!/bin/bash red="\033[31m" green="\033[32m" yellow="\033[33m" blue="\033[34m" tail="\033[0m" color(){ case $1 in red) echo -e "${red}$2${tail}" ;; green) echo -e "${green}$2${tail}" ;; yellow) echo -e "${yellow}$2${tail}" ;; blue) echo -e "${blue}$2${tail}" ;; *) echo "usage:$0 please input right content" esac } color $* [ scripts]# 功能调用颜色函数: [ scripts]# cat 09-04.sh #!/bin/bash . ./color.sh cat <<EOF 1.apple 2.pear 3.banana 4.cherry EOF read -p "请输入一个数字{1|2|3|4}:" num expr $num + 2 &>/dev/null if [ $? -ne 0 ] then echo "usage:$0 {1|2|3|4}" exit 1 fi case $num in 1) color red apple ;; 2) color green pear ;; 3) color yellow banana ;; 4) color blue cheryy ;; *) echo "usage:$0 {1|2|3|4}" exit esac [ scripts]# 字的背景颜色对应的数字范围为40-47,代码如下。 echo -e "\033[40;37m 黑底白字oldboy\033[0m" #<==40m表示黑色背景。 echo -e "\033[41;37m 红底白字oldboy\033[0m" #<==41m表示红色背景。 echo -e "\033[42;37m 绿底白字oldboy\033[0m" #<==42m表示绿色背景。 echo -e "\033[43;37m 棕底白字oldboy\033[0m" #<==43m表示棕色背景(brown),和黄色背景相近。 echo -e "\033[44;37m 蓝底白字oldboy\033[0m" #<==44m表示蓝色背景。 echo -e "\033[45;37m 洋红底白字oldboy\033[0m" #<==45m表示洋红色背景(magenta),和紫色背景相近。 echo -e "\033[46;37m蓝绿底白字oldboy\033[0m" #<==46m表示蓝绿色背景(cyan),和浅蓝色背景相近。 echo -e "\033[47;30m 白底黑字oldboy\033[0m" #<==47m表示白色背景。
rsync启动基本脚本:
[ scripts]# cat rsync.sh #!/bin/bash case $1 in start) rsync --daemon if [ $? -eq 0 ] then echo "rsync $1 ok" else echo "rsync $1 fail" fi ;; stop) killall rsync if [ $? -eq 0 ] then echo "rsync $1 ok" else echo "rsync $1 fail" fi ;; restart) killall rsync && sleep 1 && rsync --daemon if [ $? -eq 0 ] then echo "rsync $1 ok" else echo "rsync $1 fail" fi ;; *) echo "usage:$0 {start|stop|restart}" esac [ scripts]#
查看进程:lsof -i:873
rsync启动高级脚本:
cp rsyncd.sh /etc/init.d/rsyncd
chkconfig --list rsyncd
chkconfig --add rsyncd
chmod +x /etc/init.d/rsyncd
[ scripts]# cat rsyncd.sh # chkconfig: 2345 20 80 # description: rsync start stop #!/bin/bash . /etc/init.d/functions start(){ rsync --daemon retval=$? if [ $retval -eq 0 ] then action "rsync start ok" /bin/true return $retval else action "rsync start fail" /bin/false return $retval fi } stop(){ killall rsync &>/dev/null retval=$? if [ $retval -eq 0 ] then action "rsync stop ok" /bin/true return $retval else action "rsync stop fail" /bin/false return $retval fi } case $1 in start) start retval=$? ;; stop) stop retval=$? ;; restart) stop sleep 2 start retval=$? ;; *) echo "usage:$0 {start|stop|restart}" esac exit $retval [ scripts]#
十、while循环
(一)while循环语法
while 循环语法 while <条件表达式> do 指令 done
(二)范例1:
每隔2s输出系统负载情况。
[ scripts]# cat 10-01.sh #!/bin/bash while true do uptime >>/tmp/oldboy.log sleep 2 done [ scripts]#
用法 说明
sh while1.sh & 把脚本while1.sh放到后台执行(后台运行脚本时常用)*
nohup while1.sh & 使用nohup 把脚本while.sh放到后台执行。
ctl+c 停止执行当前脚本或者任务
ctl+z 暂停执行当前脚本或者任务
bg 把当前脚本或者任务放到后台执行,bg可以理解为backround
fg 把当前脚本或者任务拿到前台执行,如果有多个任务,可以使用fg加任务编号调出对应脚本任务,如fg 2,调出第二个脚本任务,fg可以理解为frontground
jobs 查看当前执行的脚本或者任务
kill 关闭执行的脚本任务,即以“kill %任务编号”的形式关闭脚本,这个任务标号,可以通过jobs获得。
后台运行 & ,nohup,screen(运维人员)
常用命令:
- kill,killall,pkill :杀掉进程
- ps:查看进程。
- pstree:显示进程状态树。
- top:显示进程。
- renice:改变优先权。
- nohup:用户退出系统之后继续工作。
- pgrep:查找匹配条件的进程。
- strace:跟踪一个进程的系统调用情况。
- ltrace:跟踪进程调用库函数的情况。
(三)范例2:
请使用while循环对下面的脚本进行修改,使得当执行脚本时,每次执行完脚本以后不退出脚本了,而是继续提示用户输入。
[ scripts]# cat 10-02.sh #!/bin/bash while true do read -t 15 -p "please input two number:" a b expr $a + $b + 2 &>/dev/null if [ $? -ne 0 ] then echo "usage:$0 please input two number." continue fi if [ -z "$b" ] then echo "usage:$0 please input two number." continue fi echo "a-b=$(($a-$b))" echo "a+b=$(($a+$b))" echo "a*b=$(($a*$b))" echo "a/b=$(($a/$b))" echo "a**b=$(($a**$b))" echo "a%b=$(($a%$b))" done [ scripts]#
(四)范例3:
猜数字游戏。首先让系统随机生成一个数字,给这个数字定一个范围(1-60),让用户输入猜的数字,对输入进行判断,如果不符合要求,就给予高或低的提示,猜对后则给出猜对用的次数,请用while语句实现。
[ scripts]# cat 10-04.sh #!/bin/bash random=$((RANDOM%60)) count=0 while true do read -p "please input a num:" num ((count+=1)) if [ $random -lt $num ] then echo "你猜大了" elif [ $random -gt $num ] then echo "你猜小了" else echo "你猜对了,NB!共计猜了${count}次!" exit 1 fi done [ scripts]#
(五)范例4:
分析Apache访问日志(access_2010-12-8.log),把日志中每行的访问字节数对应字段数字相加,计算出总的访问量。
[ scripts]# cat 10-05.sh #!/bin/bash sum=0 awk '{print $10}' access_2010-12-8.log | grep -v - >./oldboy.log while read line do ((sum=sum+line)) done <./oldboy.log echo $sum [ scripts]# sh 10-05.sh 1380681
十一、for循环语句应用实践
(一)、for循环语法
1)普通语法 for 变量名 in 变量取值列表 do 指令。。。 done 2)c语言型for循环语法 for(( exp1;exp2;exp3)) do 指令。。。 done
(一)范例1
用for循环竖向打印1、2、3、4、5共5个数字。
[ scripts]# cat 11-01.sh #!/bin/bash for n in {1..5} do echo $n done [ scripts]# sh 11-01.sh 1 2 3 4 5 [ scripts]#
(二)范例2:
通过开发脚本实现仅设置sshd rsyslog crond network sysstat服务开机自启动。
[ scripts]# cat 11-02.sh #!/bin/bash for name in sshd rsyslog crond network sysstat do chkconfig $name on done [ scripts]# chkconfig --list | grep 3:on crond 0:off 1:off 2:on 3:on 4:on 5:on 6:off network 0:off 1:off 2:on 3:on 4:on 5:on 6:off rsyslog 0:off 1:off 2:on 3:on 4:on 5:on 6:off sshd 0:off 1:off 2:on 3:on 4:on 5:on 6:off sysstat 0:off 1:on 2:on 3:on 4:on 5:on 6:off 扩展: [ scripts]# chkconfig --list | grep 3:on |awk '{print "chkconfig", $1, "off"}' | bash
(三)范例3:
计算从1加到100之和。
[ scripts]# cat 11-03.sh #!/bin/bash for n in {1..100} do ((sum=sum+$n)) done echo $sum [ scripts]# sh 11-03.sh 5050 [ scripts]# 方法2: for ((i=1;i<=100;i++)) do ((sum=sum+$i)) done echo $sum
(四)案例4:
在Linux下批量修改文件名,将文件名中的“_finished”去掉。
准备测试数据,如下。
方法1: ls *.jpg | awk -F "_finished" '{print "mv",$0, $1$2}'|bash 方法2: [ scripts]# cat 11-04.sh #!/bin/bash for file in `ls 11/*.jpg` do mv $file `echo ${file/_finished/}` done [ scripts]# 方法3: rename "_finished" "" *.jpg
十二、循环控制及状态返回值应用实践
本章将带着大家学习以下几个特殊的命令break(循环控制)、continue(循环控制)、exit(退出脚本)、return(退出函数)。
(一)、break、continue、exit、return的区别和对比
在上述命令中,break、continue在条件语句及循环语句(for、while、if等)中用于控制程序的走向,而exit则用于终止所有语句并退出当前脚本,除此之外,exit还可以返回上一次程序或命令的执行状态值给当前Shell;return类似exit,只不过return仅用于在函数内部返回函数执行的状态值。
命令 说明
break n 如果省略n表示跳出整个循环,n表示跳出循环的层数。
continue n 如果省略n表示跳过本次循环,忽略本次循环的剩余代码,进入循环的下一次循环。n表示退到第n层继续循环。
exit n 退出当前shell程序,n为上一次程序执行的状态返回值。n也可以省略,再下一个shell里可通过$?接收exit n的n值。
return n 用于在函数里,作为函数的返回值,用于判断函数执行是否正确。再下一个shell里可通过$?接收exit n的n值。
十三、Shell数组应用实践
(一)数组介绍
为什么会产生数组
通常在开发Shell脚本时,我们定义变量采用的形式为a=1;b=2;c=3,可如果有多个变量呢?这时再一个一个定义很费劲,并且要是有多个不确定的变量内容,也难以进行变量定义,此外,快速读取不同变量的值也是一件很痛苦的事情,于是数组就诞生了,它就是为了解决上述问题而来的。
什么是Shell数组
如果读者有过其他语言的编程经历,那么想必会熟悉数组的概念。简单地说,Shell的数组就是把有限个元素(变量或字符内容)用一个名字命名,然后用编号对它们进行区分的元素集合。这个名字就称为数组名,用于区分不同内容的编号就称为数组下标。组成数组的各个元素(变量)称为数组的元素,有时也称为下标变量。
有了Shell数组后,就可以用相同名字引用一系列变量及变量值,并通过数字(索引)来识别使用它们。在许多场合,使用数组可以缩短和简化程序开发。
(二)数组的定义
方法1:推荐 array=(one two three four) 方法2: array=([0]=one [1]=two [2]=three [3]=four) 方法3: [ ~]# array[0]=one [ ~]# array[1]=two [ ~]# array[2]=three [ ~]# array[3]=four [ ~]# echo ${array[@]} one two three four 方法4:命令的结果放到数组里,推荐。 array=(`ls /server/scripts`)
(三)、操作数组元素
读取数组内容:***** [ ~]# array=( 1 2 3 4 5) [ ~]# echo ${array[0]} 1 [ ~]# echo ${array[1]} 2 [ ~]# echo ${array[2]} 3 [ ~]# echo ${array[3]} 4 [ ~]# echo ${array[4]} 5 [ ~]# echo ${array[5]} [ ~]# echo ${array[*]} 1 2 3 4 5 [ ~]# echo ${array[@]} 1 2 3 4 5 [ ~]# echo ${#array[@]} 5 [ ~]# echo ${#array[*]} 5 给数组增加内容: [ ~]# array[5]=oldboy [ ~]# echo ${#array[*]} 6 [ ~]# echo ${array[*]} 1 2 3 4 5 oldboy 删除数组元素: [ ~]# unset array[1] [ ~]# echo ${array[*]} 1 3 4 oldboy [ ~]# unset array[0] [ ~]# echo ${array[*]} 3 4 oldboy 数组能不能替换: 使用for循环打印数组元素 array=(1 2 3 4 5) for n in ${array[*]} do echo $n done echo ===================== #i为数组下标 for ((i=0;i<${#array[*]};i++)) do echo ${array[i]} done array=([1]=one [2]=two [3]=three) array[0]=a;array[1]=b;array[2]=c array=($(命令)) 或 array=(`命令`)