shell中常用的控制语句及脚本运行控制

shell中常用的控制语句及脚本运行控制

学习目标:
for 语句
while 语句
if 语句
case 语句
expect 语句
exit break continue
exit直接退出当前脚本
break仅仅退出本次循环
continue 退出本次循环进行下一次循环
shell脚本中没有return命令
1.for语句:
 for NUM in {1..3}
 for NUM in `seq 1 3`或者for NUM in `seq 1 2 10`
 do
 done
1  vim file.sh
 #!/bin/bash                  
for NUM in {1..5}
do
   if
   [ "$NUM" -eq 3 ]
   then
          $1
   fi
   echo   $NUM
done
    2  sh file.sh  1
    3  sh file.sh  
    4  sh file.sh  exit #直接退出当前脚本,当NUM=3时,直接退出
    5  sh file.sh break #仅仅退出本次循环,还会执行for循环之后的内容
    6  sh file.sh continue #退出本次循环进行下一次循环
    7  sh file.sh return #没有该命令


8  vim file.sh #return
#!/bin/bash
ECHO()
{
    echo test return
}
for NUM in {1..5}
do
   if
   [ "$NUM" -eq 3 ]
   then
          return ECHO
   fi
   echo   $NUM
done
echo hello westos !!!
   9 sh file.sh
1
2
file.sh: line 11: return: ECHO: numeric argument required
file.sh: line 11: return: can only `return' from a function or sourced script
3
4
5
hello westos !!!
1.1seq 作用:
`seq 1 5`可以设置步长,可以有变量{1..5}不可以设置步长。
for语句参数可以传到循环以外,是嵌套关系,总共执行m*n次
for语句的变量仅仅最后变量被使用,循环定义变量依次执行,进行批处理。
1 vim for.sh
#!/bin/bash                  
for NUM in {a..f}
do
    echo $NUM
done
 sh for.sh #从a-f

2 vim for.sh
#!/bin/bash                  
for NUM in `seq 1 3 8`
do
    echo $NUM
done
 sh for.sh #步长为3,输出1 4 7

1.2>FOR循环
vim for.sh
#!/bin/bash                  
for A in {1..5}
do
    for NUM in {1..5}
    do
        echo $A
    done
done
echo $A
 sh for.sh #1-5各循环5次

脚本实验:

检测教室能上网的机子:

1 vim check_host.sh
2 sh check_host.sh
3 cat check_host.sh
#!/bin/bash                  
for ((A=1;A<=50;A++))
do
    ping -c1 -w1 172.25.254.$A &>/dev/null && echo 172.25.254.$A
done


脚本实验:

对数据库做备份,每个数据库备份一个文件,例如mysql.sql将文件存储到/mnt/mysql_backup

建立两个数据库两个数据表插入数据进行备份操作:
1 systemctl start mariadb
2 mysql
3 mysql -uroot  -EN -e "show databases;" | grep -E "^\*|schema$" -v #过滤出需要备份的库
4 vim mysql_backup.sh
#!/bin/bash       
DATABASE_MESSAGE=`mysql -uroot -EN -e "show databases;"|grep -E "^\*|schema$" -v`
mkdir -p /mnt/mysql_dump
for DATABASE_NAME in $DATABASE_MESSAGE #备份次数
do  
    mysqldump -uroot $DATABASE_NAME > /mnt/mysql_dump/${DATABASE_NAME}.sql
    [ "$?" -eq "0" ] && { #根据退出值判断备份是否完成
    echo -e "\033[32m$DATABASE_NAME is backuped !!\033[0m"
    }
done           

5 sh mysql_backup.sh
6 ls /mnt/mysql_dump/
 

2 while语句:
while true  条件为真就执行
do

done

脚本实验:

编写脚本当负载超过80%时发送邮件给超级用户:

  1  df -h | awk '/\/$/{print $5}' | awk -F "%" '{print $1}' #过滤出所占内存的数字
  2  echo load average | mail -s warning root
  3  mail
  4  vim mail_warning.sh
#!/bin/bash                  
DISK_NUM=`df -h | awk '/\/$/{print $5}' | awk -F "%" '{print $1}'`
#TTY=`ps $$|awk '/bash$/{print $2}'`
while true
do
     [ "$DISK_NUM" -ge "80" ]&&{
     echo "Your / will full !!" |mail -s warning root
     }
     sleep 1
done

  5  df
  6  dd if=/dev/zero of=/bigfile bs=1M count=5000 #测试当/内存超过80%,是否会发送邮件给root
  7  sh mail_warning.sh
  8  ls /var/spool/mail
  9  cat /var/spool/mail/root

3.if语句
3.1>语句示例:

if [ "$1"=="start" ]
then
systemctl start $2
elif [ "$1"=="stop" ]
then
systemctl stop $2
else
echo "error:please input start or  stop after scripts !!"
fi

3.2>固定格式:

if
then
elif
then
else
fi

写一个脚本,检测文件是否存在,如果存在,并判断文件类型

方法一:常规方法

1 vim file_check.sh
#!/bin/bash
if
[ "$#" -ne 1  ]
then
   echo ERROR
elif
[ -L "$1" ]
then
   echo $1 is a link
elif
[ -S "$1" ]
then
   echo $1 is a socket
elif
[ -b "$1" ]
then
   echo $1 is a block
elif
[ -c "$1" ]
then
   echo $1 is a common
else
 echo unknown $1
fi
2 sh check_file.sh FILENAME


方法二:vim Check_file.sh #用函数实现文件类型的检测
#!/bin/bash
Check_file
{
   if
   [ "$1" "$2" ] #$1为Check_file函数之后的$1为判断文件类型判断,$2为文件名称,即脚本后的第一串字符
   then
        echo "$2" is $3
   exit 0
   fi
}
   if
   [ "$#" -ne "1" ]
   then
        echo "Please input a file follow script!!"
   elif
   [ ! -e "$1" ]
   then
        echo  "$1 is not exist !!"
    else

        Check_file -S $1 socket
        Check_file -b $1 block
        Check_file -c $1 character
        Check_file -L $1 link
        Check_file -d $1 directory
    fi    

测试结果:


编写一个脚本:建立用户当出现以下情况报错:

1 文件数量不对报错
2 文件不存在
3 文件行数差异
4 用户存在显示用户存在,但不改变此用户密码
5 当用户不存在建立用户并设定相应密码

实验思路:
1.规则判定:Check Rule
2.动作执行:Create User
vim user_create.sh
#!/bin/bash
################## Check Rule ##################
if
[ "$#" -ne "2" ] #脚本后面有两串字符
then
   echo "ERROR1:Please input userfile and passfile follow the script!!"
   exit 1
elif
[ ! -e  "$1" ] #检测文件是否存在
then
   echo "ERROR2:Sorry, $1 is not exist !!"
   exit 1
elif
[ ! -e  "$2" ]
then
   echo "ERROR3:Sorry, $2 is not exist !!"
   exit 1
elif
USERFILE_LINE=`awk 'BEGIN{N=0}{N++}END{print N}' $1`
PASSFILE_LINE=`awk 'BEGIN{N=0}{N++}END{print N}' $2`
[ "$USERFILE_LINE" -eq "$PASSFILE_LINE" ] #检测文件行数是否对应,避免有用户没有密码
then
   echo "ERROR4:$1's line is different from $2's line !!"
   exit 1
fi


################CREATE USER################

for  LINE_NUM in `seq 1 $USERFILE_LINE` #for循环取文件中的用户名
do
     USERNAME=`sed -n ${LINE_NUM}p $1`
     PASSWORD=`sed -n ${LINE_NUM}p $2`
     useradd $USERNAME &&{   #检测建立的用户是否已经存在,当没有报错时,将密码给新建用户
     echo $PASSWORD | passwd --stdin $USERNAME
     }
done
 

实验操作步骤:

 1  vim user_create.sh
 2  sh user_create.sh #测试
 3  sh user_create.sh userfile passfile
 4  touch userfile
 5  sh user_create.sh userfile passfile
 6  touch passfile
 7  sh user_create.sh userfile passfile
 8  vim userfile
 9  sh user_create.sh userfile passfile
10  vim passfile
11  sh user_create.sh userfile passfile
12  id user1
13  userdel -r user1
14  sh user_create.sh userfile passfile
15  id user1
4.case语句:

case 同步字符匹配

4.1>case结构:

case
   word1)
   action1
   ;;
   word2)
   action2
   ;;
   ......
   *)
   action_last
   esac

4.2>case语句示例:

case $1 in
     westos)
     echo linux
     ;;
     linux)
     echo westos
     ;;
     *)

     echo "Error: input westos or  linux after script !!"

esac

4.3 >脚本实验:
写一个脚本,当$1是cat,输出为dog,当$1 是dog,输出为cat如果是其他的,输出为"please input cat or dog foolow scripts !!"

方法一:if语句

1 >vim  test.sh
#!/bin/bash
if
  [ "$1" = dog ]
then  
  echo cat
elif
  [ "$1" = cat ]
then
  echo dog
else
  echo "please input cat or dog follow script !!"
fi
上面的脚本语句有前后顺序,影响运行效率
测试:
2 sh -x test.sh dog
3 sh -x test.sh cat
4 sh -x test.sh 
方法二: case语句
1 vim case.sh
#!/bin/bash
case $1 in
        dog)
        echo cat
        ;;
        cat)
        echo dog
        ;;
        *)
        echo error
esac
2 sh -x case.sh dog
3 sh -x case.sh cat
4 sh -x case.sh

结果对比:

用非交互式删除分区:
1 fdisk -l
2 vim delete_partiton.sh
#!/bin/bash
fdisk /dev/vdb <<EOF
d
2
wq
EOF
partprobe
3 sh delete_partiton.sh
4 fdisk -l
用非交互式建立分区:$1为分区内存:

1 vim create_partiton.sh
#!/bin/bash
fdisk /dev/vdb <<EOF
n



+$1
wq
EOF
partprobe
2 sh create_partiton.sh 1G
3 fdisk -l

很明显上面的方法是有bug的,如果建立新分区时有扩展分区,但是还想建主分区,可是拓展分区占用了剩余所有的内存,是不是就会报错,此时我们就需要考虑建分区时,是否已经建立了拓展分区,如果建立了怎么办,如果没有建立怎么办?如果建立分区时已经有了拓展分区怎么办?:
vim create_partiton1.sh
#!/bin/bash
DESK_MESSAGE=`fdisk -l |awk '/Extended/'`
if
[ -z "$DESK_MESSAGE" ]
then
   fdisk /dev/vdb <<EOF
   n
   e


   wq
EOF
   partprobe
fi
5 expect
expect是自动应答命令用于交互式命令的自动执行expect是一种自动交互语言,能实现在shell脚本中为scp和ssh等自动输入密码自动登录。

spawn是expect中的监控程序,其运行后台会监控命令提出的交互问题

send 发送问题答案给交互命令

"\r" 表示回车

exp_continue 表示当问题不存在时继续回答下面的问题

expect eof   表示问题回答完毕退出expect环境

interact     表示问题回答完毕退出expect环境;//交互模式,用户会永远停在远程服务器上面

set NAME [lindex $argv n] 定义变量

命令在:

/usr/bin/expect

实验脚本:
1 vim ask.sh #自问自答
#!/bin/bash
read -p "What's your name: " NAME
read -p "How old are you: " AGE
read -p "Where are you from: " CITY
read -p "Are you happy: " FEEL
echo "$NAME is $AGE and come from $CITY ; She feel $FEEL "
2 sh ask.sh


3 yum install expect -y
4 vim answer.exp 自动应答命令用于交互式命令的自动执行
#!/usr/bin/expect
set timeout 2 //设置超时时间spawn /mnt/ask.sh //
expect "name:" //接收参数
send "liujiayi\r" 
expect "old:"
send "18\r"
expect "from:"
send "Zhouzhi\r"
expect "happy:"
send "happy\r"
expect eof

4 chmod +x /mnt/ask.sh
5 expect answer.exp

1 vim answer1.exp
#!/usr/bin/expect
set timeout 2
spawn /mnt/ask.sh
expect { //返回信息匹配
        name  { send "liujiayi\r";exp_continue }
        old   { send "18\r";exp_continue }
        from  { send "Zhouzhi\r";exp_continue }
        happy { send "happy\r" }
       }
expect eof
2 expect answer1.sh
3 vim answer2.exp
#!/usr/bin/expect
set timeout 2
set NAME [lindex $argv 0] #在expect中表示exp文件后的第一串字符,和shell中的$1相似
set AGE  [lindex $argv 1]
set CITY [lindex $argv 2]
set FEEL [lindex $argv 3]
spawn /mnt/ask.sh
expect {
        name  { send "$NAME\r";exp_continue }
        old   { send "$AGE\r";exp_continue }
        from  { send "$CITY\r";exp_continue }
        happy { send "$FEEL\r" }
       }
expect eof

4 expect answer2.exp

   

1 vim answer3.sh #脚本调用expect中的命令,实现非交互式应答
#!/bin/bash
/usr/bin/expect <<EOF
set timeout 2
spawn /mnt/ask.sh
expect {
        name  { send "$1\r";exp_continue }
        old   { send "$2\r";exp_continue }
        from  { send "$3\r";exp_continue }
        happy { send "$4\r" }
       }
expect eof
EOF
2 sh answer3.sh
3 sh answer3.sh lee 18 Dongbei happy!


连接教室里面1-10主机,并显示他们的主机名
1 vim auto_connect.sh
#!/bin/bash
for NUM in {1..10}
do
ping -c1 -w1 172.25.254.$NUM &>/dev/null && {
/usr/bin/expect <<EOF
set  timeout 3
spawn ssh [email protected].$NUM "hostname"
expect {
       "yes/no" { send "yes\r";exp_continue }
       "password" { send "$2\r" }
}
expect eof
EOF
}
done
 

连接教室里面1-10主机,并显示他们的主机名,并将他们的主机名定向到/mnt/hostame中:
1 vim auto_connect2.sh
#!/bin/bash
AUTO_CONNECT()
{
/usr/bin/expect <<EOF
set timeout 10
spawn ssh [email protected].$IP hostname
expect {
       "yes/no" { send "yes\r";exp_continue }
       "password" { send "westos\r" }
       }
expect eof
EOF
}
for IP in {64..65}
do
       ping -c1 -w1 172.25.254.$IP &>/dev/null && {
       NAME=`AUTO_CONNECT|grep -E "authenticity|ECDSA|connecting|Warning|password|spawn" -v`
       }
       echo $NAME 172.25.254.$IP | sed 's/\r//g'>>/mnt/hostname
done
2 sh auto_connect2.sh
3 ls #测试,看是否生成了hostname文件,并查看文件内容:
4 cat hostname


ctrl+v ^
ctrl+m M
^M表回车
vim auto_connecton.sh
\n\r 换行+回车
unix中\r表换行
linux中\n表换行,\r回车


猜你喜欢

转载自blog.csdn.net/dreamer_xixixi/article/details/80755328
今日推荐