模块二、shell脚本逻辑结构

fendou00sd 2020-01-29

七、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=(`命令`)

相关推荐