Shell编程之流程控制语句

简单介绍一下Shell编程中的控制流程语句,包括if条件语句、for循环、while循环、case选择语句、select选择语句、函数和数组的基本用法。

3.1 if 条件语句

3.1.1 单/双分支 if 语句
  • 单分支语句: 用于在满足某个条件时执行特定语句。

    if (条件表达式); then
        语句1
    fi
    
  • 双分支语句: 包含else分支,当条件不满足时执行另一组语句。

    if (表达式); then
        语句1
    else
        语句2
    fi
    
  • 多支条件语句: 使用elif进行多条件判断。

    if (表达式); then
        语句1
    elif (表达式); then
        语句2
    elif (表达式); then
        语句3
    fi
    
3.1.2 常见判断逻辑运算符
  • -f: 判断文件是否存在
  • -d: 判断目录是否存在
  • -eq: 整型比较,等于
  • -ne: 整型比较,不等于
  • -lt: 整型比较,小于
  • -gt: 整型比较,大于
  • -le: 整型比较,小于或等于
  • -ge: 整型比较,大于或等于
  • -a: 逻辑与
  • -o: 逻辑或
  • -z: 判断字符串是否为空
  • -x: 判断文件是否具有可执行权限
3.1.3 判断 crond 进程是否在运行的案例
#!/bin/bash
# this is check crond
name=crond
num=$(ps -ef | grep $name | grep -vc grep)
if [ $num -eq 1 ]; then
    echo "$num is running!"
else
    echo "$num is not running!"
fi
  • 该脚本通过ps -ef命令获取进程列表,并使用grep查找crond进程的数量。如果找到数量为1,则表示该进程正在运行。grep -vc grep忽略grep这个进程。
3.1.4 判断系统目录是否存在的案例
#!/bin/bash
# this is check directory
if [ ! -d /data/rivers -a ! -d /tmp/rivers ]; then
    mkdir -p /data/rivers
fi
  • 该脚本判断两个目录是否都不存在,如果不存在则创建/data/rivers目录。
3.1.5 多个条件判断学生分数等级的案例
#!/bin/bash
# this check grade shell
grade=$1
if [ $grade -gt 90 ]; then
    echo "It's very good!"
elif [ $grade -gt 70 ]; then
    echo "It's good!"
elif [ $grade -ge 60 ]; then
    echo "pass"
else
    echo "no pass"
fi
  • grade=$1 获取第一个变量
  • 该脚本根据输入的分数判断学生的等级,分数范围对应不同的输出。

3.2 for 循环语句介绍

# 格式:for name [ in [ word … ] ] ; do list ; done
for 变量名 in 取值列表; do
    语句1
done
  • for循环用于遍历一个列表中的每个值。
3.2.1 检查同一局域网多台主机是否存活的案例
#!/bin/bash
# check hosts is on/off
Network=$1
for Host in $(seq 1 254); do
    ping -c 1 $Network.$Host > /dev/null && result=0 || result=1
    if [ "$result" == 0 ]; then
        echo -e "\033[32mNetwork.$Host is up\033[0m"
        echo "$Network.$Host" >> /tmp/up.txt
    else
        echo -e "\033[31mNetwork.$Network.$Host is down\033[0m"
        echo "$Network.$Host" >> /tmp/down.txt
    fi
done
  • ping -c 1 Network.Host:这部分命令对 Network.Host 这个主机进行一次 ICMP ping 测试。-c 1 参数指定只发送一个请求。

  • 其中, > /dev/null:这是输出重定向,将 ping 命令的输出(成功信息和错误信息)丢弃,不显示在终端上。/dev/null 是一个特殊的文件,写入其内容会被丢弃。

  • && 和 ||:这是 Bash 中的逻辑运算符。

    • &&:如果前面的命令(ping)成功(返回值为 0),则执行 result=0。
    • ||:如果前面的命令失败(返回值非 0),则执行 result=1。
  • 该脚本使用ping命令检查从Network.1Network.254的每台主机是否存活,并记录结果。

3.3 while 循环语句介绍

# while (表达式)
while [ condition ]; do
    语句1
done
  • while循环在条件为真时执行语句,适用于需要重复执行的任务。
3.3.1 While循环求1-100的总和的案例
#!/bin/bash
j=0
i=1
while ((i <= 100)); do
    j=$((i + j))
    ((i++))
done
echo $j
  • 该脚本计算1到100的总和。

3.4 case 选择语句介绍

# Case选择语句
case 模式名 in
    模式1)
        命令
        ;;
    模式2)
        命令
        ;;
    *)
        不符合以上模式执行的命令
esac
  • case语句用于多个条件的选择,类似于if-elif结构。
3.4.1 使用 case 编写一个 httpd 服务启动脚本的案例
#!/bin/bash
# check http server start|stop|status
while true; do
    echo -e "选择: start, stop, status, quit"
    read -p "请输入你的选择: " char
    case $char in
        start)
            systemctl start httpd && echo "httpd服务已经开启" || echo "开启失败"
            ;;
        stop)
            systemctl stop httpd && echo "httpd服务已经关闭" || echo "关闭失败"
            ;;
        status)
            systemctl status httpd
            ;;
        quit)
            exit
            ;;
        *)
            echo "输入错误,请重新输入!"
            ;;
    esac
done
  • read: 这是一个用于从标准输入读取用户输入的命令。
    • -p: 这个选项允许你在读取输入之前打印一个提示符。这里,它会打印“请输入你的选择: ”。
    • char: 这是变量名,read 命令将用户输入的值存储在这个变量中。用户输入的内容将被赋值给 char。
  • 该脚本提供一个菜单,可以启动、停止、查看状态或退出HTTP服务。

3.5 select 选择语句介绍

# select 语句
select var in (选项); do
    命令
done
  • select用于生成一个菜单供用户选择,常用于交互式脚本。
3.5.1 使用 select 打印 lnmp 菜单栏的案例
#!/bin/bash
PS3="请选择你要安装的菜单:"
select i in http php mysql quit; do
    case $i in
        http)
            echo -e "\033[31m测试Httpd\033[0m"
            ;;
        php)
            echo -e "\033[32m测试PHP\033[0m"
            ;;
        mysql)
            echo -e "\033[33m测试MySQL\033[0m"
            ;;
        quit)
            echo -e "\033[32m退出系统\033[0m"
            exit
            ;;
        *)
            echo "输入错误,请重新输入!"
            ;;
    esac
done
  • 该脚本创建一个简单的菜单供用户选择不同的服务。
  1. #!/bin/bash: 指定脚本使用的解释器为 Bash。

  2. PS3="请选择你要安装的菜单:": 设置 select 命令的提示符,这里是当用户需要输入选择时显示的提示信息。

  3. select i in http php mysql quit; do:

    • 使用 select 命令创建一个菜单,i 将存储用户的选择。
    • 菜单选项包括 http, php, mysqlquit
    • 用户输入选项后,程序进入 dodone 之间的循环。
  4. case $i in: 开始一个 case 语句,根据用户选择的值(存储在 i 中)执行相应的操作。

当用户运行这个脚本时,会看到如下输出的菜单:

请选择你要安装的菜单: 
1) http
2) php
3) mysql
4) quit
# 这里会显示菜单选项,并等待用户输入一个数字
  • 用户输入一个数字(例如 123,或 4)后,程序将根据选择打印相应的消息。
  • 如果用户输入无效选项(即不是 1 到 4 之间的数字),程序将提示用户 输入错误,请重新输入!,然后再次显示菜单。

3.6 Shell 函数和数组编程

3.6.1. Shell 函数
定义函数

在 Shell 中,函数是一组命令的集合,可以在脚本中多次调用,避免重复代码。函数的基本定义如下:

func() {
    command1
    command2
    ...
}
函数调用

要调用定义的函数,只需使用函数名即可,不需要括号。例如:

func
示例代码
#!/bin/bash

func() {
    VAR=$((1 + 1))
    echo "This is a function."
    return $VAR
}

func
echo $?  # 输出函数的返回值,即2
  • 这里 echo $? 用于获取上一个命令(即函数)的返回值。在这个示例中,VAR 的值是 2,所以输出为 2
3.6.2. Shell 数组

数组在 Shell 中用于存储多个值,基本定义格式为:

array=(element1 element2 element3 ...)
数组定义方法
  1. 方法 1:直接初始化

    array=(a b c)
    
  2. 方法 2:通过下标添加元素

    array[0]=a
    array[1]=b
    array[2]=c
    
  3. 方法 3:命令输出作为数组元素

    array=($(command))
    
  • command: 这是你要执行的命令。命令的输出将被捕获并存储到数组中。
  • (): 用于将命令的输出分配给数组。注意要使用小括号,且需要在赋值符号=的两边没有空格。
示例1:简单命令
#!/bin/bash

# 使用 `ls` 命令获取当前目录下的文件和文件夹
files=($(ls))

# 遍历数组并打印每个文件名
echo "当前目录下的文件和文件夹有:"
for file in "${files[@]}"; do
    echo "$file"
done
  • files=($(ls)):

    • 执行 ls 命令,获取当前目录下的所有文件和文件夹。
    • 通过 $(...) 捕获命令的输出,并将其分配给数组 files。此时,files 数组中每个元素对应 ls 命令输出中的一个文件或文件夹名。
  • for file in "${files[@]}"; do ... done:

    • 使用 for 循环遍历数组 files 中的每个元素。
    • "${files[@]}" 是访问数组的语法,确保每个元素都被正确处理,特别是在元素中包含空格的情况下。

如果在一个包含文件的目录下运行这个脚本,输出可能是:

当前目录下的文件和文件夹有:
file1.txt
file2.txt
directory1
directory2
  • 空格处理: 当命令的输出包含空格时,使用 "${array[@]}" 可以避免将其拆分成多个元素。例如,如果输出中有文件名为 my file.txt,使用 "$file" 而不是 $file 可以确保整个文件名被视为一个字符串。
  • 命令输出的格式: 如果命令输出的结果很复杂,比如多行或多列数据,可能需要进一步处理以获取所需的数组元素。
示例2:使用 ps 命令

下面是一个更复杂的示例,使用 ps 命令获取当前运行的进程并将其存储在数组中:

#!/bin/bash

# 使用 `ps` 命令获取当前运行的进程
processes=($(ps -eo cmd))

# 输出每个进程的命令
echo "当前运行的进程:"
for process in "${processes[@]}"; do
    echo "$process"
done
  • ps -eo cmd: 此命令列出所有当前运行的进程的命令部分。
  • processes=($(ps -eo cmd)): 将这些命令的输出存储到 processes 数组中。
  • 输出: 遍历数组并打印每个进程的命令。
3.6.3. 安装 Apache 的函数示例
编写代码
#!/bin/bash
# auto install apache

FILES=httpd-2.2.31.tar.bz2
FILES_DIR=httpd-2.2.31
URL=http://mirrors.cnnic.cn/apache/httpd/
PREFIX=/usr/local/apache2/

function Apache_install() {
    # Install httpd web server
    if [[ "$1" -eq "1" ]]; then
        wget -c $URL$FILES && tar -jxvf $FILES && cd $FILES_DIR && ./configure
        if [ $? -eq 0 ]; then
            make && make install
            echo -e "\033[32m--------------------------------------------"
            echo -e "\033[32mThe $FILES_DIR Server Install Success !\033[0m"
        else
            echo -e "\033[31mThe $FILES_DIR Make or Make install ERROR, Please check!\033[0m"
            exit 0
        fi
    fi
}

Apache_install 1  # 调用函数,传参为1
代码逐行解释
  • wget -c $URL$FILES

    • wget 是一个下载工具,-c 选项表示如果下载中断,可以继续下载。
    • $URL$FILES 是提前定义好的变量,分别代表下载的 URL 和文件名。
    • 这个命令用于从指定的 URL 下载名为 $FILES 的压缩包。
  • && tar -jxvf $FILES

    • && 用于连接多条命令,表示前一个命令成功执行后才执行后面的命令。
    • tar -jxvf 用于解压缩 bzip2 压缩格式的 tar 包。
      • -j 表示使用 bzip2 解压缩。
      • -x 表示解压缩文件。
      • -v 表示详细显示解压缩过程。
      • -f 表示后面跟的是要解压的文件名。
    • $FILES 是下载的压缩包名称。
  • && cd $FILES_DIR

    • cd 是改变目录的命令,用于进入解压后的文件夹。
    • $FILES_DIR 是提前定义的变量,代表解压缩后得到的目录名。
  • && ./configure

    • 执行 ./configure 命令进行预编译配置,生成 Makefile
    • ./configurehttpd 安装的第一步,检查系统环境和依赖项,以便生成适合系统的编译配置。
  • if [ $? -eq 0 ]; then

    • $? 是上一条命令执行的返回状态码。
    • 0 表示上一条命令成功执行。
    • 这里判断 ./configure 是否执行成功,如果成功则继续执行下一步。
  • make && make install

    • make 用于根据 Makefile 编译源代码。
    • make install 用于将编译后的程序安装到指定的位置(一般是系统路径中)。
    • 这里用 && 连接,表示只有 make 成功后才执行 make install
  • echo -e "\033[32m--------------------------------------------"

    • echo -e 用于打印带有转义字符的字符串。
    • \033[32m 是 ANSI 转义码,用于将输出文本颜色设置为绿色。
    • 打印出分隔线,方便阅读输出信息。
  • echo -e "\033[32mThe $FILES_DIR Server Install Success !\033[0m"

    • 打印安装成功的提示信息。
    • \033[0m 是 ANSI 转义码,用于重置文本颜色。
    • 如果安装成功,显示绿色文本提示 The $FILES_DIR Server Install Success !
  • else

    • 如果 ./configuremake 的执行失败,进入 else 分支。
  • echo -e "\033[31mThe $FILES_DIR Make or Make install ERROR, Please check!\033[0m"

    • 打印错误提示信息。
    • \033[31m 将文本颜色设置为红色,提示用户安装过程中出现了错误。
    • \033[0m 重置文本颜色。
  • exit 0

    • 终止脚本的执行,返回状态码 0(一般表示正常退出)。
    • 这里用于在出现错误时停止脚本继续执行。
3.6.4. 遍历数组元素
方法 1:使用下标遍历
#!/bin/bash
IP=(10.0.0.1 10.0.0.2 10.0.0.3)
for ((i=0; i<${#IP[*]}; i++)); do
    echo ${IP[i]}
done
  • ${#IP[*]} 获取数组 IP 的长度,即数组中元素的数量。
    • 用于获取数组的长度。
    • IP 是数组变量。
    • ${#IP[*]} 获取数组 IP 中的所有元素个数。
    • [*] 表示获取数组的所有元素,可以换成 [@],在获取数组长度时两者效果相同。
方法 2:使用 for 循环遍历
#!/bin/bash
IP=(10.0.0.1 10.0.0.2 10.0.0.3)
for ip in "${IP[@]}"; do  # 使用引号确保处理包含空格的元素
    echo $ip
done
  • ${IP[@]}
    • [@] 是用于获取数组 IP 中所有元素的一种方式。
    • IP[@] 表示数组 IP 中的所有元素。
    • ${IP[@]} 会将数组的每个元素展开为独立的值。
    • 如果数组 IP 包含多个元素,这个语法会将它们全部传递给 for 循环。
数组遍历的输出

示例 3.6.4和3.6.5 的输出内容是

10.0.0.1
10.0.0.2
10.0.0.3
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值