shell编程(七) : [shell基础] 使用结构化命令

接上一篇文章Linux shell编程(六): 基本shell脚本

3.2 使用结构化命令

前面介绍的都是顺序执行的命令,有时需要按照逻辑顺序执行命令,这是就需要对命令命令施加一些逻辑流程控制,这样的命令通常称为结构化命令。

3.2.1 判断语句

if-then

最基本的结构化命令就是 if-then 语句。格式如下:

if command
then
	commands
fi

与大多数编程语言的 if 语句不同,bash shell 的 if 后面不是判断条件语句的真假,而是当 if 后面的 command 的退出状态码为 0 时,位于 then 部分的 commands 就会被执行,fi 语句表示 if-then 语句到此结束。

有时为了使 bash shell 的 if-then 语句看起来更舒服一点,也可以把 thenif 语句放在同一行,并用 ; 隔开,如下:

if command; then
	commands
fi
if-then-else

当 if 语句中的命令返回退出状态码 0 时, then 部分中的命令会被执行,当 if 语句中的命令返回非零退出状态码时,bash shell会执行 else 部分中的命令,如下:

if command1; then
	commands1
else 
	commands2
fi

嵌套 if

就像其他编程语言的 if 语句一样,bash shell也可以使用嵌套if,如下:

if command1; then
	commands1
elif command2; then
	commands2
elif command3; then
	commands3
else
	commands4
fi

其中,elifelse if 的简写。

test命令

有个不幸的消息,bash shell 的 if 语句后面只能判断命令退出的状态码,注意,是 只能

但有个好消息是,可以使用一些命令实现判断其他的条件,比如 test 命令,其格式如下:

test condition

其中 condition 是 test 命令要测试的一系列参数和值,即条件语句,当 condition 的值是 true 时,test condition 的退出状态码为 0

在这里插入图片描述

由于 a 是空的,所以 $a 条件语句的值是 falsetest $a 的退出状态码就是非零的,所以执行了 else 语句。

bash shell提供了另一种和 test 语句功能一样的条件测试方法——方括号 [],格式是如下:

if [ condition ]
then
	commands
fi

其中,第一个方括号之后和第二个方括号之前必须加上一个空格,否则就会报错。

他们可以判断下面三类条件:

  • 数值比较
  • 字符串比较
  • 文件比较

接下来介绍怎么使用这些条件。

1. 数值比较

这里的数值比较不是用 > = < 等符号,而是有一套专用的符号,如下:

比较符号 描述
-eq (equal) 等于
-ge (greater or equal) 大于等于
-gt (greater then) 大于
-le (less or equal) 小于等于
-lt (less than) 小于
-ne (not equal) 不等于

示例如下:

在这里插入图片描述

也可以使用方括号:

在这里插入图片描述

注意,方括号和所包含内容之间要用空格隔开。

另外,以上方法不支持浮点数的比较。

2. 字符串比较

以上方法还支持字符串比较,但比较符号不同

比较 描述
str1 = str2 str1 和 str2 相同
str1 != str2 str1 和 str2 不相同
str1 \< str2 str1 小于 str2
str1 \> str2 str1 大于 str2
-n str1 str1 的长度不为0
-z str1 str1 的长度为0

注意小于和大于符号前面的 \ ,它是转义符号,如果没有它bash shell会把 <> 当成重定向符号。

其中,大于和小于的判断,是根据ASCII码的数值排序的。

示例如下:

在这里插入图片描述

-n 和 -z 可以检查一个变量是否为空,如下:

在这里插入图片描述

3. 文件比较

文件比较可以测试Linux文件系统上文件和目录的状态。

参数如下:

参数 描述
-d object 检查 object 是否存在并是一个目录
-e object 检查 object 是否存在(文件和目录都使适用)
-f object 检查 object 是否存在并是一个文件
-r object 检查 object 是否存在并可读
-s object 检查 object 是否存在并非空
-w object 检查 object 是否存在并可写
-x object 检查 object 是否存在并可执行
-O object 检查 object 是否存在并属当前用户所有
-G object 检查 object 是否存在并且默认组与当前用户相同
object1 -nt object2 检查 object1 是否比 object2 新
object1 -ot object2 检查 object1 是否比 object2 旧

示例:

#!/bin/bash

if [ -d ./test ]; then
    touch ./test/test.txt
else
    mkdir ./test
    touch ./test/test.txt
fi

检测当前目录下是否存在 test 目录,如果存在,在 test 目录里新建 test.txt 文件,如果不存在,新建 test 目录后,再在 test 目录里新建 test.txt 文件。其余使用方法同理。

bash shell 的 if-then 语句同样支持布尔逻辑,&&|| ,如下:

#!/bin/bash

if [ -d ./test/test.txt ] && [ -w ./test/test.txt ]; then
	echo "The file exists and you can write to it."
else
	echo "cannot write to the file."
fi

test 命令只能操作简单的数学表达式,if-then 还有高级特性可以支持更丰富的功能。

  • 用于数学表达式的双括号:(( expression ))
  • 用于高级字符串处理的双方括号:[[ expression ]]

双括号除了支持 test 命令支持的标准数学运算外,还支持以下运算符:

符号 描述
val++(++val) 自增
val–(--val) 自剪
! 逻辑非
~ 按位取反
** 幂运算
<< 按位左移
>> 按位右移
& 按位取与
| 按位取或
&& 逻辑与
|| 逻辑或

可以在 if 语句中用双括号命令,也可以在脚本中的普通命令里使用来赋值,如下:

#!/bin/bash

val1=10
if (( $val1 ** 2 > 90 ))
then
	(( val2 = $val1 ** 2 ))
	echo "The square of $val1 is $val2"
fi

-----------------------------------------
The square of 10 is 100

双方括号除了支持 test 命令支持的标准字符串比较外,还支持 模式匹配

在模式匹配中,可以定义正则表达式来匹配字符串值,如下:

#!/bin/bash

if [[ $USER == v* ]]
then
	echo "Hello $USER"
else
	echo "Sorry, I do not know you"
fi

-----------------------------------------
Hello vistar

正则表达式在后面会介绍到。

3.2.2 分支语句

case 命令

case 命令采用列表格式来检查单个变量的多个值,如下:

#!/bin/bash

case $USER in
rich | barbara)
	echo "Welcome, $USER"
	echo "Please enjoy your visit";;
testing)
	echo "Special testing account";;
jessica)
	echo "Do not forget to log off when you're done";;
*)
	echo "Sorry, you are not allowed here";;
esac

其中注意几点:

  • case 语句以 case 开头,以 esac 结尾。
  • 在每个分支程序之后要以 ;;(双分号)结尾。
  • 星号 *) 会捕获所有与已知模式不匹配的值。

3.2.3 循环语句

for 命令

for 命令的基本格式如下:

for var in list
do
	commands
done

其中 var 是迭代变量, list 是需要迭代的值的列表(每个值用空格分隔,包含空格的值用双引号括起来),commands 是循环体,如下:

在这里插入图片描述

也可以将要迭代的值存在变量里,然后在for循环语句中引用这个变量:

在这里插入图片描述

麻烦的是,包含空格的值仍然需要放在for循环语句中。不过这个问题还是有办法解决的,就是更改内部字段分隔符,它通过环境变量 IFS 定义,默认情况下,字段分隔符为 空格制表符换行符。如果想使用其他的符号作为字段分隔符,可以修改环境变量 IFS 的值,如下:

在这里插入图片描述

也可以指定多个字段分隔符,只需要在为IFS赋值时将多个符号串起来即可:

在这里插入图片描述

也可以使用命令的输出作为循环的迭代列表:

在这里插入图片描述

c语言风格的for循环语句

还记得支持复杂数学表达式的双括号码,双括号也可以使bash shell支持c语言风格的for循环语句。

在这里插入图片描述

while命令

while 命令会在每次迭代的一开始测试 test 命令。在 test 命令返回非零退出状态码时, while 命令会停止执行那组命令。

while 命令的格式如下:

while test command
do
	other commands
done

其中, test command 和 if-then 语句中的格式一样。

while 命令允许在 while 语句行定义多个测试命令。但只有最后一个测试命令的退出状态码会被用来决定什么时候结束循环。注意,多个测试命令时,每个命令占一行,如下:

在这里插入图片描述

until命令

until 命令和 while 工作方式相反,只有测试命令的退出状态码不为 0 ,bash shell才会执行循环中列出的命令,一旦测试命令返回了退出状态码 0 ,循环就结束了,其他特性和 while 命令一样,不再赘述,其格式如下:

until test commands
do
	other commands
done
break 命令

可以用 break 命令来退出任意类型的循环,包括for、while 和 until 循环。

break 命令有一个和其他编程语言不同的功能,就是它能 “远程控制” 别的循环,一般的编程语言的break只能跳出当前循环,但bash shell的 break 可以接收一个参数 n ,指定要停止的循环,n 默认为1,即当前循环。示例如下:

#!/bin/bash

for (( a = 1; a < 2; a++ ))
do
    echo "3 loop: a=$a"
    for (( b = 1; b < 4; b++ ))
    do
        echo "    2 loop: b=$b"
        for (( c = 1; c < 100; c++ ))
        do
            if [ $c -gt 4 ]
            then
                break 2
            fi
            echo "        1 loop: c=$c"
        done
        echo "    2 loop: b=$b"
    done
    echo "3 loop: a=$a"
done

输出如下:

在这里插入图片描述

首先,外层循环 3 执行了1次,输出 a=1,然后进入内层循环 2,内层循环 2 执行1次,输出 b=1,然后进入内层循环 1 ,内层循环 1 判定如果 c>4则执行 break 2,该命令的意思是从当前层循环往外层开始数,连续跳出2层循环,事实也是这样,当 c=4 时又执行下一个循环 b=5,此时满足判定条件,直接跳到了外层循环 319 行的命令,输出 a=1 ,然后执行外层循环 3 的第 3 行命令 a++,此时 a=2,然后判定是否 a<2,判定失败,结束外层循环 3 ,程序结束。

continue命令

break 命令一样,continue 命令除了基本的停止本次循环继续下次循环的功能外,也可以使用参数停止外层循环。如下:

#!/bin/bash

for (( a = 1; a <= 5; a++ ))
do
    echo "Iteration $a:"
    for (( b = 1; b < 3; b++ ))
    do
        if [ $a -gt 2 ] && [ $a -lt 4 ]
        then
            continue 2
        fi
        var3=$[ $a * $b ]
        echo "    The result of $a * $b is $var3"
    done
done

在这里插入图片描述

代码第 8 行,当 a=3 时,执行 continue 2,同 break 2 一样,2 代表从当前层循环往外层开始数的第2层循环,continue 2 的意思即停止外层循环 a=3 的这一次循环,继续执行 a=4 的循环。

处理循环的输出结果

可以对循环的输出使用管道或进行重定向,如下:

将循环的输出重定向到文件。

#!/bin/bash

for str in $(ls /home)
do
    echo "Holle $str"
done > output.txt

在这里插入图片描述

也可以使用管道,将循环的输出结果传给其他命令,作其他处理。

#!/bin/bash

for str in $(ls /home)
do
    echo "Holle $str"
done | grep vistar

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/maizousidemao/article/details/123101469