shell脚本的编写之循环

1.for循环

1.1语法

方法一:
for 变量 in 取值列表
  do
    命令列表
  done
  
for 变量 in 取值列表;do
  
    命令列表
  done

方法二:
for NAME [in WORDS ... ] ; do COMMANDS; done


方法三:
for ((初始值;循环变化条件;变量变化))    ##类C风格
   do
     命令列表
   done

1.2实例

1>批量创建多用户
#!/bin/bash
for name in `cat /mnt/a.txt`    #提前创建好a.txt,用户名每行一个
do
	id $name &> /dev/null
	if [ $? -ne 0 ];then
		useradd $name
		echo "123456" | passwd --stdin $name &> /dev/null
	else
		echo "user $name is exist "
	fi
done
2>批量创建用户,将用户加入到hopu组中
#!/bin/bash
grep -w ^hopu /etc/group &>/dev/null

if [ $? -ne 0 ];then
    groupadd hopu 
fi
  for ((i=1;i<=5;i++))
 do
   useradd -G hopu user$i
   echo 123456 |passwd --stdin user$i
 done
3>计算1到100的总数值
方法1)
echo {1..100}|tr ' ' +|bc

方法2)
#!/bin/bash
sum=0
for i in {1..100}
  do
      let sum+=i
  done
   echo "sum=$sum" 
   
==========   
方法3:C风格脚本
#!/bin/bash
for ((sum=0,i=1;i<=100;i++));do
      let sum+=i
  done
  echo $sum
4>使用for循环来检查192.168.10.0网段IP地址是否联通

#!/bin/bash
ip=192.168.10

for ((i=1;i<=255;i++))
  do
    ping -c1 -i 0.2 $ip.$i &>/dev/null
  if [ $? -eq 0 ];then
      echo "$ip.$i is up" >>/tmp/ip_up.txt
   else
      echo "$ip.$i is down" >>/tmp/ip_down.txt
  fi
  done  
  

#shell脚本并发控制测试
{程序}&表示将程序放到后台执行,如果需要等待程序执行完在进行下面的内容,就在done的后面加wait
#!/bin/bash
ip=192.168.10

for ((i=1;i<=254;i++))
  do
  {
    ping -c1 -i 0.2 $ip.$i &>/dev/null
  if [ $? -eq 0 ];then
      echo "$ip.$i is up" >>/tmp/ip_up.txt
   else
      echo "$ip.$i is down" >>/tmp/ip_down.txt
  fi
   }&

  done
wait
  echo "ip 地址检查完毕!"
5>计算1-100之间的奇数的值
方法1:
#!/bin/bash
sum=0
for i in {1..100..2}
  do
     let sum=sum+$i
     done
  echo sum=$sum
  
方法2:
#类c风格写法:
#!/bin/bash
sum=0
  for ((i=1;i<=100;i+=2))
    do
      let sum=sum+$i
     done
      echo sum=$sum
6>打印九九乘法表
语法1:
  #!/bin/bash
set -ue
for i in {1..9}
do
    for j in `seq $i`
    do
        echo -en "${i}x${j}=$((i*j))\t"
    done
    echo ""
done

======
语法2:C风格的
#!/bin/bash
for ((i=1;i<=9;i++));do
 for((j=1;j<=i;j++));do
    echo -en "${j}x$i=$((j*i))\t"
done
   echo
done

2.while循环

2.1语法

语法格式一:
while [条件]
do
    操作
done

语法格式二:
while read line
do
    操作
done  <  file

通过read命令每次读取一行文件,文件内容有多少行,while循环多少次

2.2实例

1>打印1-5
#!/bin/bash
i=1
  while [ $i -le 5 ]
  do
    echo $i
      let i++
done
2>计算10以内平方数
#!/bin/bash
num=1
while [ $num -lt 10 ]
do
	sum=$(expr $num \* $num)
	echo "$num * $num = $sum"
	#let num++
	((num++))
done

=========
#!/bin/bash
num=1
while [ $num -lt 10 ]
do
    sum=$((num*num))
    echo "$num * $num = $sum"
     #let num++
     ((num++))
      done                 

2.3无限循环模式

2.3.1 语法
方法一:
while :
do
  命令
done
方法二:
for (( ; ; ))
方法三:
while true
do
   命令
done
2.3.2实例
1>猜价格
#!/bin/bash
price=50
times=0

echo "商品的实际价格为0-99之间,猜猜看是多少? " 
while true
do
	read -p "input a price: " int
	let times++
	if [ $int -eq $price ];then
		echo "恭喜,猜对了"
		echo "你一共猜了 $times 次"
		exit 105
	elif [ $int -gt $price ];then
		echo "猜大了"
	else
		echo "猜小了"
	fi
done
2>查看系统信息
#!/bin/bash
echo "请根据下面的提示选择查看对应的功能"
while :
do
cat <<EOF
h 显示查看帮助信息
f 显示查看内存使用信息
d 显示查看磁盘使用信息
p 显示查看系统负载信息
q 退出!
EOF

read -p "请根据上面的序号选择对应的功能:" sys

case $sys in 
   h|H)
cat <<EOF
   h 显示查看帮助信息
   f 显示查看内存使用信息
   d 显示查看磁盘使用信息
   p 显示查看系统负载信息
   q 退出!
EOF
   ;;
   f|F)
    free -h
   ;;
   d|D)
    df -h
    ;;
   p|P)
    uptime
    ;;
 q|Q)
   exit
  ;;
 esac
done

3until循环

3.1语法

和while刚好相反,只要不满足条件就一直循环
until expression  
do 
    command 
done

3.2实例

1>打印1到100的值
#!/bin/bash
# 定义变量的初始值
 i=1
 sum=0

# until循环
until (($i > 100))
  do
   let sum=$sum+$i
   let i++
  done
echo "1-100之间的和:$sum"
2>使用until批量创建10个用户,要求用户是从stu1-stu10,要求设置用户的家目录在/mnt/stu
#!/bin/bash

i=1

if [ -d /mnt/user ];then
    echo "/mnt/stu目录已经存在"
else
    mkdir /mnt/user

fi

until [ $i -gt 10 ]
   do
   if  [ $i -le 10 ];then
      useradd -d /mnt/user/stu$i stu$i && echo "123456"|passwd --stdin stu$i
   else
     echo "user is exist"
    fi
   let i++
  done

4. 循环语句嵌套

4.1概念

**关键字:大圈套小圈**

1. 一个循环体内又包含另一个**完整**的循环结构,称为循环的嵌套。
2. 每次外部循环都会触发内部循环,直至内部循环完成,才接着执行下一次的外部循环。
3. for循环、while循环和until循环可以**相互**嵌套。

4.2语法

方法一:
for    变量1   in
              do
                     for    变量2    in
                            do
                                   命令2
                            done
              命令1
       done
方法二:
for    变量1   in
              do
                if […];then
         fi
              命令1
       done

4.3实例

1>添加用户脚本
#!/bin/bash
#add user
while :
do
	read -p "please enter prefix & password & num: " prefix pass num
	printf "user information: 
	-------------------------
	user prefix: $prefix
	user passwd: $pass
	user number: $num
	-------------------------
"
for i in `seq -w $num`
do
	user=${prefix}${i}
	id $user &> /dev/null
	if [ $? -ne 0 ];then
		useradd $user && echo "$pass" | passwd --stdin $user &> /dev/null
	    if [ $? -eq 0 ];then
			echo -e "\e[31m$user\e[0m created"
		fi	
	else
		echo "user $user exist"
	fi
done
  exit 100
done
2>写一个收集服务器的内存的脚本,当内存使用率大于80%时发送告警
#!/bin/bash
date=`date +"%F %T"`
percentage=30
while true;
do
mem_usage=`free -m | sed -n '2p'|awk '{ print ($3+$6)/$2*100 }'`
if [ `expr "$mem_usage > $percentage"` ]; then                                                                                                                                    
  echo  "memory's warning $date  memory:$mem_usage%" |mail -s "warning" wuchaofengainio@163.com
   else
  echo "memory is normal"
  echo "$mem_usage%"
fi
  sleep 30
done
3>打印指定的图形
5
54
543
5432
54321

方法1:
#!/bin/bash
y=5
while (( $y >= 1 ));do
    for ((x=5;x>=$y;x--));do
            echo -n $x
	done
			echo
		let y--
	done

方法2:
#!/bin/bash
for (( y=5;y>=1;y--))
do
        for (( x=5;x>=$y;x--))
        do
        echo -n $x
        done
echo
done

# 直角三角形
*
**
***
****
*****

#!/bin/bash
for ((i=1;i<=5;i++));do
	for((j=1;j<=i;j++));do
    	echo -e "*\c"
	done
   		echo
done

# 等腰三角形
         *
        ***
       *****
      *******
     *********
     
#!/bin/bash
for ((i=1;i<=10;i++));do
	for ((k=1;k<=10-i;k++));do
		echo -e " \c"
	done
        for((j=1;j<=2*i-1;j++));do
            echo -e "*\c"
        done
            echo
	done
4>使用while循环来判断http服务是否正常,如果异常则启动服务,并记录服务启动时间,反之就打印服务正常。
#!/bin/bash

# 定义HTTP服务的URL
url="http://192.168.1.100"

# 定义最大尝试次数
max_attempts=5

# 定义当前尝试次数
current_attempt=0

# 定义服务启动日志文件路径
log_file="/mnt/log/file.log"
# 判断HTTP服务是否正常
while [ $current_attempt -lt $max_attempts ]; do
    # 发送HTTP请求
    response=$(curl -s -o /dev/null -w "%{http_code}" $url)

    # 检查HTTP响应状态码
    if [ $response -eq 200 ]; then
        echo "HTTP service is up and running." >> $log_file
        break
    else
        echo "HTTP service is down. Attempt $current_attempt." >> $log_file
        # 在这里添加启动HTTP服务的命令,例如:
         systemctl start httpd &>> $log_file
          if [ $? -eq 0 ];then
            echo "http服务启动成功"
          else
            echo "http服务启动失败"
       fi
        current_attempt=$((current_attempt + 1))
    fi
done

5.exit语句

5.1概念

exit 是一个Shell内置命令,用来退出当前 Shell 进程,并返回一个退出状态;使用$?可以接收这个退出状态。0表示成功,其他数字表示失败

5.2语法

exit [返回值]

5.3案例

1>判断输入的是否是数字
#!/bin/bash

read -t 30 -p "please input num: "  num

y=$( echo $num | sed 's/[0-9]//g' )

if [ -n "$y" ]
then
	echo "please input number,error!!!!"
	exit 120
else	
    echo $num

fi 

输出
[root@ali01 ~]# ./exit.sh 
please input num: ws
please input number,error!!!!
[root@ali01 ~]# echo $?
120
[root@ali01 ~]# 

注意:exit是退出当前进程,在脚本中的应用就是退出当前脚本进程,也就是执行到exit后,直接退出,不再执行后续命令,所以说,exit需要谨慎写入,确保执行完你想要的效果后再退出。

2>判断输入是否是yes/no
#!/bin/bash
read -p "请输入(yes|no):" al
case $al in
"yes")
        echo    "您输入的是yes"
        exit 1                                #当选择的是yes后,程序就退出了,不在打印“您的选择是yes”这句话。
        echo    "您的选择是yes"
        ;;
"no")
        echo    "您输入的是no"
        echo    "您的选择是no哦"
        ;;
*)
        echo    "输入错误,请输入yes|no"
esac

6.提前结束循环语句

6.1break

6.1.1语法
break n
n 表示跳出循环的层数,如果省略 n,则表示跳出当前的整个循环。break 关键字通常和 if 语句一起使用,即满足条件时便跳出循环。
6.1.2案例
1>判断输入的数字是否大于0,如果小于等于0则循环终止
#!/bin/bash
echo "请输入大于0的数字"
sum=0
while read num; do
    if ((num>0)); then
        ((sum+=num))
    else
        break
    fi
done
echo "sum=$sum"
6.1.3使用 break 跳出双层循环
#!/bin/bash
for((i=1; i<=10; i++)); do
    for((j=1; j<=10; j++)); do
        if ((i*j==12)); then
            break
        fi
        printf "%d*%d=%-4d" $i $j $((i*j))   #%s %c %d %f都是格式替代符,-表示将左对齐,不加-表示右对齐
    done
    printf "\n"
done



输出
[root@localhost shells]# bash break.sh 
1*1=1   1*2=2   1*3=3   1*4=4   1*5=5   1*6=6   1*7=7   1*8=8   1*9=9   1*10=10  
2*1=2   2*2=4   2*3=6   2*4=8   2*5=10  
3*1=3   3*2=6   3*3=9   
4*1=4   4*2=8   
5*1=5   5*2=10  5*3=15  5*4=20  5*5=25  5*6=30  5*7=35  5*8=40  5*9=45  5*10=50  
6*1=6   
7*1=7   7*2=14  7*3=21  7*4=28  7*5=35  7*6=42  7*7=49  7*8=56  7*9=63  7*10=70  
8*1=8   8*2=16  8*3=24  8*4=32  8*5=40  8*6=48  8*7=56  8*8=64  8*9=72  8*10=80  
9*1=9   9*2=18  9*3=27  9*4=36  9*5=45  9*6=54  9*7=63  9*8=72  9*9=81  9*10=90  
10*1=10  10*2=20  10*3=30  10*4=40  10*5=50  10*6=60  10*7=70  10*8=80  10*9=90  10*10=100 

6.2 continue

6.2.1语法
continue n

- 如果省略 n,则表示 continue 只对当前层次的循环语句有效,遇到 continue 会跳过本次循环,忽略本次循环的剩余代码,直接进入下一次循环。
- 如果带上 n,比如 n 的值为 2,那么 continue 对内层和外层循环语句都有效,不但内层会跳过本次循环,外层也会跳过本次循环,其效果相当于内层循环和外层循环**同时**执行了不带 n 的 continue
6.2.2案例
1>打印1-10的数字
#!/bin/bash

for (( i=1;i<=10;i=i+1 ))
do
        if [ "$i" -eq 4 ]
        then
                continue
        fi


        echo $i
done
6.2.3使用 continue 跳出双层循环
#!/bin/bash
for((i=1; i<=10; i++)); do
    for((j=1; j<=10; j++)); do
        if ((i*j==12)); then
            continue 
        fi
        printf "%d*%d=%-4d" $i $j $((i*j))
    done
    printf "\n"
done     


输出
[root@localhost shells]# bash continue2.sh 
1*1=1   1*2=2   1*3=3   1*4=4   1*5=5   1*6=6   1*7=7   1*8=8   1*9=9   1*10=10  
2*1=2   2*2=4   2*3=6   2*4=8   2*5=10  2*7=14  2*8=16  2*9=18  2*10=20  
3*1=3   3*2=6   3*3=9   3*5=15  3*6=18  3*7=21  3*8=24  3*9=27  3*10=30  
4*1=4   4*2=8   4*4=16  4*5=20  4*6=24  4*7=28  4*8=32  4*9=36  4*10=40  
5*1=5   5*2=10  5*3=15  5*4=20  5*5=25  5*6=30  5*7=35  5*8=40  5*9=45  5*10=50  
6*1=6   6*3=18  6*4=24  6*5=30  6*6=36  6*7=42  6*8=48  6*9=54  6*10=60  
7*1=7   7*2=14  7*3=21  7*4=28  7*5=35  7*6=42  7*7=49  7*8=56  7*9=63  7*10=70  
8*1=8   8*2=16  8*3=24  8*4=32  8*5=40  8*6=48  8*7=56  8*8=64  8*9=72  8*10=80  
9*1=9   9*2=18  9*3=27  9*4=36  9*5=45  9*6=54  9*7=63  9*8=72  9*9=81  9*10=90  
10*1=10  10*2=20  10*3=30  10*4=40  10*5=50  10*6=60  10*7=70  10*8=80  10*9=90  10*10=100 

6.3break 和 continue 的区别

break 用来结束所有循环,循环语句不再有执行的机会;continue 用来结束本次循环,直接跳到下一次循环,如果循环条件成立,还会继续循环

7 位移 shift

shift命令用于对参数的移动(左移),通常用于在不知道传入参数个数的情况下依次遍历每个参数然后进行相应处理

7.1 shift语法

shift [num]

7.2 实例

1>打印参数个数

#!/bin/bash
while [ "$1" ];do
echo "第一个参数为:$1,参数个数为:$#"
  shift
  done



输出
[root@localhost shells]# bash shift.sh a b c d
第一个参数为:a,参数个数为:4
第一个参数为:b,参数个数为:3
第一个参数为:c,参数个数为:2
第一个参数为:d,参数个数为:1

从上可知 shift(shift 1) 命令每执行一次,变量的个数($#)减一 (之前的$1变量被销毁,之后的$2就变成了$1),而变量值提前一位。
2>创建用户

#!/bin/bash
#********************************************************************
#Author: wcfeng
#QQ: 452495750
#Date: 2022-01-09
#FileName: shift_adduser.sh
#Description: The test script
#********************************************************************
while [ $1 ];do
    if id $1 &>/dev/null;then
        echo $1 is exist!
    else
        useradd $1
    fi
      shift
   done
    echo "All user is created"

输出
[root@localhost shells]# bash shift_adduser.sh user1 user2 user3
All user is created
[root@localhost shells]# tail -3 /etc/passwd
user1:x:1003:1003::/home/user1:/bin/bash
user2:x:1004:1004::/home/user2:/bin/bash
user3:x:1005:1005::/home/user3:/bin/bash

3>使用shifts实现计算器效果

#!/bin/bash
sum=0
while [ $# -ne 0 ]    #判断参数的个数是否为0,如果不为0则开始计算
 do
   let sum=$sum+$1
  shift
 done
 echo $sum

输出
[root@localhost shell]# bash shift2.sh 1 2 3
6

8 函数

8.1 概念

将一段代码组合封装在一起实现某个特定的功能或返回某个特定的值,然后给这段代码取个名字,也就是函数名,在需要实现某个特定功能的时候直接调用函数名即可。

简单的说,函数的作用就是把程序多次调用相同的代码部分定义成一份,然后为这一份代码定义一个名字,其它所有重复调用这部分代码就都只调用定义的这个名字就可以了,当需要修改这部分重复代码时,只需要修改函数体内的一部分代码即可实现所有调用修改。

8.2优势

①把相同的程序定义成函数,可以减少整个程序的代码量

②增加程序的可读性、异读性,以及可管理性。

③可以实现程序功能模块化,不同的程序使用函数模块化。

函数名的定义和定义变量的规则基本一致,但是函数名允许以数字开头。

8.3语法

function name() {
    statements
    [return value]
}

对各个部分的说明:

  • function是 Shell 中的关键字,专门用来定义函数;
  • name是函数名;
  • statements是函数要执行的代码,也就是一组语句;
  • return value表示函数的返回值,其中 return 是 Shell 关键字,专门用在函数中返回一个值;这一部分可以写也可以不写。

{ }包围的部分称为函数体,调用一个函数,实际上就是执行函数体中的代码。

8.4定义的简化写法

如果你嫌麻烦,函数定义时也可以不写 function 关键字:
name() {
    statements
    [return value]
}

如果写了 function 关键字,也可以省略函数名后面的小括号:
function name() {
    statements
    [return value]
}

8.5调用脚本

8.5.1 脚本中调用
[root@localhost shell]# cat fun2.sh 
#!/bin/bash

 hello(){
   echo "您好,欢迎下次光临!"
   }


[root@localhost shell]# cat fun3.sh 
#!/bin/bash

menu() {
cat <<-EOF
欢迎选购,今日水果清单如下:
1.苹果
2.香蕉
3.菠萝
4.橘子
5.猕猴桃
EOF
  }
menu
source /root/shell/fun2.sh
read -p "请输入你要选择的水果编号:" num
case $num in
  1)
  echo 您选择的是苹果;;
  2)
  echo 您选择的是香蕉;;
  3)
  echo 您选择的是菠萝;;
  4)
  echo 您选择的是橘子;;
  5)
  echo 您选择的是猕猴桃;;
  *)
  echo 请选择1-5之间的数字;;
esac
 hello

8.6 函数返回值

8.6.1 return 返回值 – 即函数的执行状态
 Shell 中的 return 返回值表示的是函数的退出状态:默认的返回值为 0 表示函数执行成功了,返回值为非 0 表示函数执行失败(出错)了。if、while、for 等语句都是根据函数的退出状态来判断条件是否成立。函数执行失败时,我们可以自定义return返回值,这样就可以根据返回值(退出状态)来判断具体出现了什么错误,比如一个打开文件的函数,我们可以指定 1 表示文件不存在,2 表示文件没有读取权限,3 表示文件类型不对。

案例
1>定义return返回的状态码

#!/bin/bash

function test() {
  echo "arg=$1"
  if [ $1 == 1 ]; then
    return 111
  else
    return 100
  fi
}

test 1
echo "该函数的执行状态值为$?"

输出

[root@ali01 ~]# bash func6.sh 22
arg=10
该函数的执行状态值为100
[root@ali01 ~]# vim func6.sh 
[root@ali01 ~]# bash func6.sh 22
arg=1
该函数的执行状态值为111
8.6.2 echo 返回值 – 获取函数处理后的结果

案例

#!/bin/bash
 
 function blreturn(){
    echo "这个函数会对输入的两个数字进行相加运算..."
    echo "输入第一个数字: "
    read aNum
    echo "输入第二个数字: "
    read anotherNum
    echo "两个数字分别为 $aNum 和 $anotherNum !"
    return $(($aNum+$anotherNum))
}
blreturn
echo "输入的两个数字之和为 $? !"

输出

[root@ali01 ~]# ./function3.sh 
这个函数会对输入的两个数字进行相加运算...
输入第一个数字: 
34
输入第二个数字: 
12
两个数字分别为 34 和 12 !
输入的两个数字之和为 46 !

函数返回值在调用该函数后通过 $? 来获得。

8.7 函数参数

$0 取脚本的文件名及路径
$1,$2 给脚本传参数
$* 把一堆参数集合成一个参数,传给脚本
$# 一共传了多少个参数
$$ 脚本的pid
$? 上一个脚本执行的返回值
$@ 与$*类似,区别是每个参数是分开的
8.7.1 案例

1>打印位置参数的值

#!/bin/bash

function parm(){
    echo "第一个参数为 $1 !"
    echo "第二个参数为 $2 !"
    echo "第十个参数为 $10 !"
    echo "第十个参数为 ${10} !"
    echo "第十一个参数为 ${11} !"
    echo "参数总数有 $# 个!"
    echo "作为一个字符串输出所有参数 $* !"
}
parm 1 2 3 4 5 6 7 8 9 34 73

输出

[root@ali01 ~]# bash function4.sh 
第一个参数为 1 !
第二个参数为 2 !
第十个参数为 10 !
第十个参数为 34 !
第十一个参数为 73 !
参数总数有 11 个!
作为一个字符串输出所有参数 1 2 3 4 5 6 7 8 9 34 73 !

**注意:**当n>=10时,需要使用${n}来获取参数。

2>数组传参

#!/bin/bash
arr=(1 2 3 4 5)
get_sum() {
  sum=0
  for i in $*;do
    let sum+=i
  done
  echo $sum
}

echo "get the array sum is `get_sum ${arr[@]}`"

输出

[root@ali01 ~]# ./func5.sh 
get the array sum is 15

3>判断网址是否正常运行

#!/bin/bash
 function chuancan() {           #定义一个chuancan函数提醒用户输入一个网址
   echo "$0 请输入一个网址"     #取脚本的文件名及路径及请输入一个网址!
  exit 1
 }

 function jc_url() {   #定义一个jc_url的函数检测用户输入参数是否正确及检测结果
  wget $1 &>/dev/null #若用户输入传参数是正确的,就执行wget命令
 if [ "$?" -eq 0 ]     #判断以上命令执行是否有误
  then
      echo "$1 Httpd is Running... " #若判断以上命令无误,输入用户传参数及检测结果
  else
      echo "$1 Httpd is Stoped..."  #若判断以上命令有误,输出用户传参数及检测结果
      exit 1
 fi
 }
 
 function panduan() {  #定义最后结果的函数
 if [ "$#" -ne 1 ]    #如果用户输入的传参数不是1
  then               #那么
       chuancan     #调用chuancan函数
 fi
       jc_url $1    #如果用户输入的传参数是1,那么就调用jc_url 函数
 }
 
 panduan $* #把命令行接收的所有参数传给函数内部

输出

[root@localhost ~]# bash func2.sh www.baidu.com
www.baidu.com Httpd is Running...

4>检查web服务是否启动

1、检查web服务是否启动

#!/bin/sh
. /etc/init.d/functions
start_nginx=/application/nginx/sbin/nginx
USAGE()
{      
   echo "USAGE $0 {start|stop|restart}"
   exit 1
}
if [ $# -ne 1 ]
   then
       USAGE
fi
if [ "$1" == "start" ]
   then
       $start_nginx
       action "start nginx" /bin/true
elif [ "$1" == "stop" ]
   then
       killall nginx
       action "stop nginx" /bin/true
 
elif [ "$1" == "restart" ]
   then
       pkill nginx
       sleep 2
       $start_nginx
       action "restart nginx" /bin/true
else
   USAGE
   exit 1
fi

9 expect

TCL(Tool command language)是一种类似shell脚本的语言,你可以使用它来完成许多操作。expect是从它发展出来的。如果你想要写一个能够自动处理输入输出的脚本(如向用户提问并且验证密码)又不想面对C或者Perl,那么expect是你的最好的选择
expect是在tcl基础上创建起来的,它还提供了一些tcl所没有的命令,它可以用来做一些linux下无法做到交互的一些命令操作

9.1 安装

[root@localhost shell]# yum -y install  expect

9.2 使用expect

1)定义脚本执行的shell

#!/usr/bin/expect

这里定义的是expect可执行文件的链接路径(或真实路径),功能类似于bash等shell功能

2)set timeout 30

   设置超时时间,单位是秒,如果设为timeout -1 意为永不超时

3)spawn 

   spawn 是进入expect环境后才能执行的内部命令,如果没有装expect或者直接在默认的SHELL下执行是找不到spawn命令的。不能直接在默认的shell环境中进行执行主要功能,它主要的功能是给ssh运行进程加个壳,用来传递交互指令。

4)expect

   这里的expect同样是expect的内部命令

   主要功能:判断输出结果是否包含某项字符串,没有则立即返回,否则就等待一段时间后返回,等待时间通过timeout进行设置

5)send

   执行交互动作,将交互要执行的动作进行输入给交互指令

   命令字符串结尾要加上**"\r"**,如果出现异常等待的状态可以进行核查

6)exp_continue

   继续执行接下来的交互操作

7)interact

   执行完后保持交互状态,把控制权交给控制台;如果不加这一项,交互完成会自动退出

8)$argv

   expect 脚本可以接受从bash传递过来的参数,可以使用 [lindex $argv n]获得,n从0开始,分别表示第一个,第二个,第三个……参数

9.3 案例

1>无交互登录服务器创建新用户

#!/usr/bin/expect

# set host ip

set ipaddress "192.168.1.101"

#set loginuser

set name "root"

#set password

set passwd "1"

#set timeout

set timeout 30

#spawn

spawn ssh $name@$ipaddress

expect {

"yes/no" { send "yes\r";exp_continue }

"password" { send "$passwd\r" }

}


#interact

expect "#"

send "useradd user1\r"

send "pwd\r"

send "touch /opt/hello.txt\r"

send "exit\r"

expect eof

10 数组

10.1定义

数组的特性就是一组数据类型相同的集合(不包括有一些编程语言提出来的关联数组的概念)

数组中可以存放多个值。Bash Shell 只支持一维数组(不支持多维数组)

与大部分编程语言类似,数组元素的下标由 0 开始。

10.2基本数组

10.2.1 基本数组定义

1>数值类型:一对括号表示数组,数组中元素之间使用“空格”来隔开。

arr_number=(1 2 3 4 5);

2>字符串类型:使用一对括号表示数组,其中数组中的元素使用双引号或者单引号包含,同样使用“空格”来隔开。

array_name=(value1 value2 ... valuen)

arr_string=("abc" "edf" "sss"); 或者 arr_string=('abc' 'edf' 'sss');

user=(`cat /etc/passwd|cut -d: -f1`)

stu=(lisa tom jarry "miss zhang")

读取数组

${array_name[index]}

10.2.2 实例
1>定义数组

方法一:一次定义一个
[root@localhost shell]#arr[0]=1
[root@localhost shell]#arr[1]=2
[root@localhost shell]#arr[2]=3
[root@localhost shell]#arr[3]=4

方法二:一次定义多个
[root@localhost shell]# arr1=(1 2 3 4)

2>读取数组中的元素

[root@itbest shell]# echo ${arr[0]}
1
[root@itbest shell]# echo ${arr[1]}
2
[root@itbest shell]# echo ${arr[2]}
3
[root@itbest shell]# echo ${arr[3]}
4

3>数组中替换元素的值

[root@localhost shell]# arr2=(1 2 3 4)
[root@localhost shell]# echo ${arr2[*]}
1 2 3 4
[root@localhost shell]# arr2[1]=5
[root@localhost shell]# echo ${arr2[*]}
1 5 3 4

4>数组中增加新元素的值

[root@localhost shell]# arr2=(1 2 3 4)
[root@localhost shell]# arr2[6]=5    
[root@localhost shell]# echo ${arr2[*]}
1 2 3 4 5

注意:当添加的元素的长度大于已存在的数组的长度时,默认值时添加在组数的最后

5>删除数组中的值

[root@localhost shell]# unset arr2[1]
[root@localhost shell]# echo ${arr2[*]}
1 3 4
[root@localhost shell]# 

[root@localhost shell]# unset arr2   --清除整个数组的值
[root@localhost shell]# echo ${arr2[*]}

6>数组的切片

[root@localhost ~]# arr3=(1 2 3 4)
[root@localhost ~]# echo ${arr3[*]:1}
2 3 4
[root@localhost ~]# echo ${arr3[@]:1}
2 3 4

10.3 关联数组
10.3.1定义关联数组
方法一:声明关联数组(一次赋一个值)

#声明一个关联数组
declare -A ass_array1
ass_array1[name]='zhangsan'
ass_array1[age]=20

#执行结果
echo ${ass_array1[name]}

方法二:声明关联数组(一次赋多个值)

#声明一个关联数组
declare -A ass_array2

ass_array2=([name]=lisi [age]=30)
echo ${ass_array2[name]}

执行结果

#执行结果
[root@localhost ~]# bash ass_arr1.sh 
lisi
[root@localhost ~]# 

10.3.2查看关联数组
1>查看关联数组

[root@localhost ~]# declare -A ass_array2
[root@localhost ~]# ass_array2=([name]=lisi [age]=30)
[root@localhost ~]# declare -A    ##查看关联数组
declare -A BASH_ALIASES='()'
declare -A BASH_CMDS='()'
declare -A ass_array2='([name]="lisi" [age]="30" )'

2>访问数组元素

[root@localhost ~]# echo ${ass_array2[name]}    ##访问下标为name的元素
lisi
[root@localhost ~]# echo ${ass_array2[@]}      ##获取所有的元素
lisi 30
[root@localhost ~]# echo ${#ass_array2[@]}      ##获取元素的个数
2
[root@localhost ~]# echo ${!ass_array2[@]}      ##获取索引
name age

10.3.3实战案例
1>学生信息查询系统

#!/bin/bash
for((i=0;i<3;i++))
do
read -p "输入第$((i+1))个人名:" name[$i]
read -p "输入第$[$i+1]个年龄:" age[$i]
read -p "输入第`expr $i + 1`个性别:" gender[$i]
done
   clear
  echo -e "\t\t\t学生信息查询系统"
while :
  do
read -p "输入要查询的姓名:" xm
[ $xm == "q" ] && exit
for((i=0;i<3;i++))
  do
  if [ "$xm" == "${name[$i]}" ];then
echo "姓名:${name[$i]} 年龄:${age[$i]} 性别:${gender[$i]}"
  fi
done
done

2> 统计web网站的不同状态连接数

#!/bin/bash
declare -A array1

# 统计连接数个数
#states=$(netstat -antup |grep 80|awk -F" " '{print $6}')
states=$(ss -ant|grep 80|cut -d ' ' -f1)

 for i in $states
  do
     let array1[$i]++
  done

#遍历打印数组中的索引和元素的个数
 for j in ${!array1[@]}
  do
    echo $j:${array1[$j]}
  done

3>遍历列表中的水果

#!/bin/bash

# 定义一个数组变量
fruits=("苹果" "香蕉" "橙子" "葡萄" "西瓜")

# 循环遍历数组元素
for fruit in "${fruits[@]}"
do
    echo "水果: $fruit"
done

# 获取数组的长度
length=${#fruits[@]}
echo "数组的长度: $length"

# 获取数组的特定元素
echo "第一个水果: ${fruits[0]}"
echo "最后一个水果: ${fruits[length-1]}"

# 修改数组元素
fruits[2]="草莓"
echo "修改后的数组: ${fruits[@]}"
  • 16
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值