shell编程-流程控制(if case)、循环(for while )、函数(function)、数组、正则表达式RE

一、shell编程-流程控制

shell编程-条件结构
测试
test 条件
条件为真返回 0,条件为假返回 1
[ 条件 ]
test 能够理解3种类型的表达式 
1.文件测试
2.字符串比较
3.数字比较
字符串
    -n STRING
    # -n 字符串长度不为零
    -z STRING
    # -z  字符串长度为0
     STRING1 = STRING2
    # = 判断两个字符串是否一样
     STRING1 != STRING2
    # != 判断两个字符串是否不一样
数字
    eq 等于       ne 不等于  #
    ge 大于等于    le 小于等于   #
    gt 大于       lt 小于   #
文件
test
    -f 存在且是普通文件  # 重要
    -d 存在且是目录  #
    -h 存在且是符号链接 
    -b 块设备
    -c 字符设备
    -e 文件存在  #
shell分支if语句
流控制:
•在一个shell脚本中的命令执行顺序称作脚本的流。大多数脚本会根据一个或多个条件来改变它们的流。 
•流控制命令:能让脚本的流根据条件而改变的命令称为条件流控制命令 
•exit语句:退出程序的执行,并返回一个返回码,返回码为0正常退出,非0为非正常退出,例如: 
•exit 0
​
条件判断
If代码返回0表示真,非0为假
if语句语法如下:   1
if [ $1 -eq 1 ]
then
      echo '等于1'
elif [ $1 -eq 2 ]
then
            echo '等于二'
else
            echo '既不等一,也不等于二'
fi
​
例:
#!/bin/bash
read -p "请输入号码: " num 
if [ $num = 1 ];then
        echo "1"
elif [ $num = 2 ];then
                echo "2"
else 
                echo "输入有误!"
fi
​
例:脚本if.sh,必须在脚本后加上适当的参数脚本才能正确执行 
#!/bin/bash
if [ "$1" = "hello" ]; then
        echo "Hello! How are you ?"
elif [ "$1" = "" ]; then
                echo "You MUST input parameters"
else
                echo "The only accept parameter is hello"
fi
​
练习(选做):
1)检测apache是否运行,如果没有运行则启动,并记录启动的时间,保存到日志中。 
2)测试ip地址主机位从2到100的机器是否存活,并把存活的机器记录到文本文件alivehost.txt内。(使用ping命令)
​
多个条件联合
逻辑与
if [ $condition1 ] && [ $condition2 ] 
if [ $condition -a $condition2 ]
if [[ $condition1 && $condition2 ]]
逻辑或
if [ $condition1 ] || [ $condition2 ] 
if [ $condition -o $condition2 ]
if [[ $condition1 || $condition2 ]]
# test 和 [] 中 我们可以使用 [ $condition1 ] && [ $condition2 ] 或者 [ $condition -a $condition2 ]
​
# 在 [[]] 这种情况,我们可以直接使用[[ $condition1 && $condition2 ]]
建议在if中直接使用[[]]这种方式,这种方式更加稳定。[[]] shell的一个命令。
-a &&  逻辑与 and 两端的条件都可以成立
-o ||  逻辑或 or  两端的条件有一段成立就行
​
练习:
编写脚本port.sh,执行脚本后显示系统的httpd、ftp、ssh、sendmail这些服务是否开启
​
case
case 语句是 shell 中流控制的第二种方式,语法如下: 
case $word in
     pattern1)
                        list1
                        ;; 
     pattern2)
                        list2
                        ;; 
     patternN)
            listN
            ;;
         *)
                        list*
                        ;; 
esac
命令;;表明流应该跳转到case语句的最后,类似C语言中的break指令。
练习:建立脚本case.sh,当执行时,要求我们在键盘输入适当的值(one|two|three),当输入正确时并打印,当输入错误 时会提示你,应该输入正确的值。
shell 分支case语句
case $var in
模式1)
                执行1
                ;;
模式2)
                执行2
                ;;
模式3)
                执行3
                ;;
*)
                执行4
esac
​
第一行: 声明case关键字调用case语法, 紧跟的“变量”一般为用户的输入值, in代表从下方的各个模式进行匹配 
第2-4行: 匹配到“模式1”后进行命令的输出或执行, 模式1: 一般为字符或数值
第11-12行: 当用户输入的字符不存在匹配模式时, 直接执行或打印*)下的命令或语句

示例:

[root@bavdu shell_scripts]# vim system_tools
#!/usr/bin/env bash
cat <<-EOF 
+-------------------------------------------------------------------------+ 
|                             System_tools V1.0                           | 
+-------------------------------------------------------------------------+
|                     a. Stop And Disabled Firewalld.                     |
|                     b. Disabled SELinux Secure System.                  |
|                     c. Install Apache Service.                          |
|                     d. Quit                                             | 
+-------------------------------------------------------------------------+ 
EOF
echo "Please input your select: " && read var
case "$var" in
    "a")
        systemctl stop firewalld && systemctl disable firewalld
                ;; 
        "b")
                setenforce 0
                ;; 
        "c")
                yum -y install httpd httpd-tools
                ;; 
        "d")
                exit
                ;; 
            *)
                printf "请按照上方提供的选项输入!!!\n"
                ;; 
esac

二、shell编程-循环结构

shell循环-for语句
for i in {取值范围}    # for 关键字  i 变量名 in 关键字  取值范围格式 1 2 3 4 5
do                    # do 循环体的开始
                循环体
done                  # done 循环体的结束 
#!/usr/bin/env bash
#
# Author:
# Date: 2019/**/**
for i in {1..100} 
do
                echo $i 
done
#!/bin/bash         # 类似c语言的循环方式
for (( i=1;i <= 5;i++ ))
do
                echo "$i"
done

测试生产环境的主机存活性

#!/usr/bin/env bash #
# Author:       #{}&  并发
>ip_alive.txt     # 在执行脚本之前,先将文件清空
>ip_down.txt
segment="192.168.161" 
for i in {2..254}
do
        {
        ping -c1 $segment.$i &>/dev/null 
        if [ $? -eq 0 ];then
                        printf "alive: $segment.$i\n" >>ip_alive.txt
        else
                        printf "down: $segment.$i\n" >>ip_down.txt
        fi
        }& 
done
wait    #等待循环结束后,执行下面操作
echo "finish..."

for循环批量创建用户

#!/bin/bash 
while :     #死循环
do
read -p "请设置用户前缀/数量/密码: " prefix num pass 
cat <<-EOF                 # 打印到屏幕
用户前缀:$prefix
用户数量:$num
用户密码:$pass
EOF
read -p "是否确认创建:[Y/N]" action 
if [ $action = Y ];then
     "starting create users..." 
     break
fi
done
for i in `seq -w $num`
do
    user=$prefix$i
    id $user &>/dev/null 
    if [ $? -eq 0 ];then
          echo "$user  is already exist"
    else
          useradd $user
          echo $pass | passwd --stdin $user &>/dev/null  # 用户密码设置不需要交互
    fi 
done
shell 循环while语句
while 条件    # while 关键字  条件  [ $1 -lt 10 ] ,while循环,条件为真的情况下,会循环
do
        循环体
done

完善系统工具的输出及操作性

创建一个文件里面的用户
#!/bin/bash
while read user
do
        id $user &>/dev/null 
        if [ $? -eq 0 ];then
                echo "$user is already exists"
        else
                useradd $user
                echo "create $user successfully"
        fi
done < user.txt
​
​
#!/usr/bin/env bash
#
# Author:
while 1>0 
do
cat <<-EOF 
+-------------------------------------------------------------------------+ 
|                            System_tools V1.0                            | 
+-------------------------------------------------------------------------+
|                      a. Stop And Disabled Firewalld.                    |
|                      b. Disabled SELinux Secure System.                 |
|                      c. Install Apache Service.                         |
|                      d. Quit                                            | 
+-------------------------------------------------------------------------+
EOF
    echo " Please input your select: " && read var
    case "$var" in
                "a")
                    systemctl stop firewalld && systemctl disable firewalld
                            ;; 
                "b")
                            sed -ri s/SELINUX=enforcing/SELINUX=disabled/g /etc/selinux/config
                            ;; 
                "c")
                            yum -y install httpd httpd-tools
                            ;; 
                "d")
                            exit
                            ;; 
                  *)
                            echo "请按照上方提供的选项输入!!!"
                            ;; 
        esac
    if [ $? -eq 0 ];then 
            clear
    else
        echo "Warning: Your program exist ERROR!!!"
        break
    fi 
done
​
练习题:
输出用户输入的参数,直到用户输入 "end" 结束循环
​
#!/usr/bin/bash
while 2>1
do
    read -p "请输入: " word
    if [ $word != 'end' ];then
        echo "$word"
    else
        echo "退出循环"
        break
    fi
done
shell循环until语句
until 条件 # 当后面的条件表达式,为假的时候进行循环,当他为真了就停止循环了。
do
循环体
done
[root@newrain ~]# cat until.sh 
#!/bin/bash
x=1
until [ $x -ge 10 ]
do
        echo $x
        x=`expr $x + 1` 
done
x=1
​
while [ ! $x -ge 10 ]
do
        echo $x
        x=`expr $x + 1`
done
shell 循环控制shift、continue、break、exit
shift命令
位置参数可以用shift命令左移。比如shift 3表示原来的$4现在变成$1,原来的$5现在变成$2等等,原来的$1、$2、$3丢 弃,$0不移动。不带参数的shift命令相当于shift 1。
对于位置变量或命令行参数,其个数必须是确定的,或者当 Shell 程序不知道其个数时,可以把所有参数一起赋值给变量 $*。
若用户要求 Shell 在不知道位置变量个数的情况下,还能逐个的把参数一一处理,也就是在 $1 后为 $2,在 $2 后面为 $3 等,则需要用shift把所有参数变成$1
#测试 shift 命令(x_shift3.sh)
[root@newrain shell]# cat x_shift3.sh 
#!/bin/bash
shift
echo "第一个位置参数: $1"
[root@newrain shell]# bash x_shift3.sh 2 3
第一个位置参数: 3
​
#测试 shift 命令(x_shift.sh) 
#!/bin/bash
until [ $# -eq 0 ]
do
echo "第一个参数为: $1 参数个数为: $#" 
shift
done
执行以上程序x_shift.sh: 
$./x_shift.sh 1 2 3 4
结果显示如下:
第一个参数为: 1 参数个数为: 4 
第一个参数为: 2 参数个数为: 3 
第一个参数为: 3 参数个数为: 2 
第一个参数为: 4 参数个数为: 1
​
从上可知 shift 命令每执行一次,变量的个数($#)减一,而变量值提前一位
​
用 until 和 shift 命令计算所有命令行参数的和。 
#shift 上档命令的应用(x_shift2.sh)
sum=0
​
until [ $# -eq 0 ] 
do
        sum=`expr $sum + $1`
        shift 
done
echo "sum is: $sum"
执行上述程序: 
        $x_shift2.sh 10 20 15
其显示结果为:
        45
​
continue、break、exit命令
Linux脚本中的break continue exit return 
​
break
结束并退出本次循环
​
continue 
在循环中不执行continue下面的代码,转而进入下一轮循环
​
exit
退出脚本
常带一个整数给系统,如 exit 0
​
可理解为:break是立马跳出循环;continue是跳出当前条件循环,继续下一轮条件循环;exit是直接退出整个脚本 
例如: 
在循环过程中,有时候需要在未达到循环结束条件时强制跳出循环,Shell使用两个命令来实现该功能:break和continue。 
break命令
break命令允许跳出所有循环(终止执行后面的所有循环)。
下面的例子中,脚本进入死循环直至用户输入数字大于5。要跳出这个循环,返回到shell提示符下,需要使用break命令。 
代码如下:
#!/bin/bash
while :
do
        echo -n "请输入1-5之间的数字 " 
        read aNum
        case $aNum in
        1|2|3|4|5) 
                echo "您的数字是 $aNum!"
        ;;
        *) echo "您输入的数字不再1-5中间,游戏结束!"
                        break 
                ;;
        esac 
done
continue命令
continue命令与break命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。 
对上面的例子进行修改:
代码如下:
#!/bin/bash
while :
do
        echo -n "请输入1-5之间的数字  " 
        read aNum
        case $aNum in
        1|2|3|4|5) 
                echo "您的数字是 $aNum!"
        ;;
        *) 
                echo "您输入的数字不再1-5中间,游戏结束!";、
                        continue 
                ;;
        esac 
done
​
运行代码发现,当输入大于5的数字时,该例中的循环不会结束.
break和exit的区别
[root@newrain shell]# cat case07.sh 
#!/bin/bash
while true
do
read -p "请输入[1/2]" num1
case $num1 in
1) 
        echo $num1
;;
2)
        while true 
        do
                read -p "再次输入[1/2]:" num2 
                        case $num2 in
                                1) echo $num2;;
                                2) break;             #将此处换成exit,再次尝试
                        esac
        done
esac
done
实战-shell版本jumpserver开发(堡垒机)

ps:整理自己的思路,完善不足的地方

#!/usr/bin/env bash
#
# Author:
#可以先添加上账密验证环节
while :        # 死循环
do
    #trap ':' INT EXIT TSTP TERM HUP  # 拒绝 ctrl+c ctrl+d 其他的退出方式
    clear
cat <<-EOF 
+-------------------------------------+
|        JumpServer @Version1.0       | 
+-------------------------------------+
| a. WebServer Apache.                |
| b. MySQL Databases Server.          |
| c. PHP Development Computer.        |
| d. Quit                             |
+-------------------------------------+
EOF
    read -p "请输入你要登录的服务器编号: "  computer
    case $computer in
    a)
            ssh jumper@192.168.161.129                     # 可以嵌套子case循环
            ;; 
    b)
            ssh jumper@192.168.161.130
            ;; 
    c)
            ssh jumper@192.168.161.131
            ;; 
    d)
            exit
            ;; 
    *)
        printf "ERROR: Please redo your select!"
            ;; 
    esac
done

三、shell 编程-函数

function (功能) 功能函数
​
完成特定功能的代码片段
函数必须先定义才能使用
优点:避免重复的代码
​
定义函数  1 怎么定义 2 定义什么东西
调用函数  1 可以本地调用,也可以调用别的脚本的函数 2 在不调用之前,它相当于没有
取消函数  1 把函数名想象成一个变量名
函数传参  1 跟脚本传参很类似
​
命名空间  1 在shell语言中命名空间函数内和函数外是一致的,函数内外不能赋值同样名字的变量
    local  1 声明一个本地变量(局部变量) 
返回值
    return value 
    value不能超过0-255
shell 函数function

函数声明

function_name () {
   list of commands
}

函数名 function_name,这就是你将使用它从其他地方在你的脚本调用。

取消函数

unset myfunc //取消函数
myfunc()  //函数定义
{
echo “This is my first shell function” 
}
myfunc    //函数调用

产生以下执行结果

./test.sh
This is my first shell function
函数必须提前定义测试
[root@newrain fun]# cat fun05.sh 
#!/bin/bash
fun () {
echo "hello"
}
fun
unset fun
fun
[root@newrain fun]# bash fun05.sh
hello
fun05.sh: line 8: fun: command not found
函数的返回值,返回的是函数体内最后一条命令是否成功的返回值
[root@newrain fun]# systemctl stop httpd 
[root@newrain fun]# cat fun03.sh 
#!/bin/bash
fun() {
        systemctl status httpd &>/dev/null
        systemctl status vsftpd &>/dev/null
}
fun 
echo $?
[root@newrain fun]# systemctl stop vsftpd
[root@newrain fun]# bash fun03.sh 
3

函数传参 在Shell中,调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数

示例

[root@newrain fun]# cat fun06.sh 
#!/bin/bash
fun() {
        echo $[$1*$2*$3]
}
fun 1 2 3
修改版:
[root@newrain fun]# cat fun06.sh 
#!/bin/bash
if [ ! $# -eq 3 ];then
        echo "Must Input Three number: p1 p2 p3"
exit fi
fun() {
        echo $[$1*$2*$3]
}
fun $1 $2 $3

四、shell 编程-数组

普通数组:只能用整数作为数组的索引 关联数组:可以使用字符串作为数组的索引

数组定义
普通数组定义:
[root@newrain shell]# books=( linux shell awk sed )  
引用:
[root@newrain shell]# echo ${books[0]}
linux
[root@newrain shell]# echo ${books[1]}
shell
[root@newrain shell]# echo ${books[2]}
awk
​
关联数组需要提前声明
declare -A myarry1
[root@newrain shell]# declare -A myarry1
[root@newrain shell]# myarry1=([name]=newrain [sex]=man [age]=26) 
[root@newrain shell]# echo ${myarry1[name]}
newrain
[root@newrain shell]# echo ${myarry1[age]}
26
定义方法1:
    # declare -a myarry=(5 6 7 8) 
    # echo ${myarry[2]}
        显示结果为 7
        
定义方法2:
    # array=( one two three four five six )
    # array2=(tom jack alice)
    # array3=(`cat /etc/passwd`)
    # array4=(tom jack alice "bash shell")
    # array5=(1 2 3 4 5 6 7 "linux shell" [20]=saltstack)
    
定义方法3: # 普通数组下标只能是数字
#!/bin/bash 
area[11]=23 
area[13]=37 
area[51]="UFOs"
访问数组

当设置任何数组变量时,可以访问它

[root@newrain shell]# aa=(haha heihei baibai)
[root@newrain shell]# echo ${aa[0]}    //访问数组中的第一个元素
[root@newrain shell]# echo ${aa[@]}         //访问数组中所有的元素,等同与echo ${aa[*]}
[root@newrain shell]# echo ${#aa[@]}   //统计元素的个数
[root@newrain shell]# echo ${!aa[@]}   //统计索引

${array_name[index]} //引用

示例

#!/bin/bash
NAME[0]="BJ"
NAME[1]="SH"
NAME[2]="SZ"
NAME[3]="GZ"
NAME[4]="HZ"
NAME[5]="ZZ"
echo "First Index: ${NAME[0]}"
echo "Second Index: ${NAME[1]}"
echo "sixth Index: ${NAME[5]}"

输出结果为

 $./test.sh
First Index: BJ 
Second Index: SH 
sixth Index: ZZ

您可以访问数组中的所有项目通过以下方式之一:

${array_name[*]}
${array_name[@]}

示例

#!/bin/sh
NAME[0]="BJ"
NAME[1]="SH"
NAME[2]="SZ"
NAME[3]="GZ"
NAME[4]="HZ"
echo "First Index: ${NAME[*]}"
echo "Second Index: ${NAME[@]}"

输出结果

 $./test.sh
First Index: BJ SH SZ GZ HZ 
Second Index: BJ SH SZ GZ HZ

疑难点 shell数组中"*" 和 "@" 区别

关于在shell脚本中数组变量中 “*”跟 “@” 区别
“*”当变量加上“” 会当成一串字符串处理. 
“@”变量加上“” 依然当做数组处理. 
在没有加上“” 的情况下 效果是等效的.

示例

#!/usr/bin/env bash
array=(gz cloud 19)
echo "case 1"
for line in "${array[@]}"
do
        echo $line
done
​
echo "case 2"
for line in "${array[*]}"
do
        echo $line
done
​
echo "case 3"
for line in ${array[*]}
do
        echo $line
done
​
echo "case 4"
for line in ${array[@]}
do
        echo $line
done

执行结果

case 1
gz
cloud
19
case 2
gz cloud 19
case 3
gz
cloud
19
case 4
gz
cloud
19
遍历数组while
[root@newrain array]# cat array01.sh 
#!/bin/bash
#++ i 是先自加1后赋值;i ++ 是先赋值后自加1。 
while read line
do     
        host[i++]=$line  # 观察i++ 和 ++i的区别
done </etc/hosts
for i in ${!host[@]}   # 数组的元素索引
do
        echo "$i:${host[i]}"
done
遍历数组for
[root@newrain array]# cat array02.sh 
#!/bin/bash
IFS=''
for line in `cat /etc/hosts`  # 读取文件中的每一行
do
        host[j++]=$line
done
for i in ${!host[@]}
do
        echo ${host[i]}
done 
以上两个脚本都是读取文件中的行,然后加到一个数组中并进行遍历。
​
练习题:统计shell的种类和数量
思路:最后一列的sh种类不同,我们可以单独取出最后一列 /etc/passwd

五、正则表达式RE


正则表达式基本元字符

正则表达式拓展元字符

用来处理文本

正则表达式(Regular Expression, RE)是一种字符模式, 用于在查找过程中匹配指定的字符. 在大多数程序里, 正则表达式都被置于两个正斜杠之间;

例如/l[oO]ve/就是由正斜杠界定的正则表达式, 它将匹配被查找的行中任何位置出现的相同模式. 在正则表达式中,元 字符是最重要的概念

元字符使正则表达式具有处理能力。所谓元字符就是指ß那些在正则表达式中具有特殊意义的专用字符,可以用来规定 其前导字符(即位于元字符前面的字符)在目标对象中的出现模式。

No.1 正则表达式基本元字符
基本正则表达式元字符 
元字符
示例                      功能
^                       行首定位符
^love 
​
$                       行尾定位符
love$ 
​
.                       匹配单个字符
l..e  
​
*                       匹配前导符0到多次
ab*love 
​
.*                      匹配任意多个字符  (贪婪匹配
​
[]                      匹配方括号中任意一个字符
[lL]ove
​
[ - ]                   匹配指定范围内的一个字符
[a-z0-9]ove             
​
[^]                     匹配不在指定组里的字符
[^a-z0-9]ove 
​
\                       用来转义元字符
love\.                  
​
\<                      词首定位符 #由数组或字母组成的
\<love
​
\>                      词尾定位符
love\>
​
\(\)                    匹配后的标签   # 在vim中测试
No.2正则表达式拓展元字符
= 等于 != 不等于  =~  匹配
扩展正则表达式元字符
+                       匹配一个或多个前导字符
[a-z]+ove
​
?                       匹配零个或一个前导字符 
lo?ve
​
a|b                     匹配a或b
love|hate
​
()                      组字符loveable|rs
love(able|rs) ov+ ov+ (ov)+ 
​
(..)(..)\1\2            标签匹配字符  #
(love)able\1er
​
x{m}                    字符x重复m次
o{5}
​
x{m,}                   字符x重复至少m次
o{5,}
​
x{m,n}                  字符x重复m到n次
o{5,10}
  • 15
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值