shell 编程(6) 之结构化控制
for 循环
列表中的值出现特殊符号时,使用引号将其括起来,以免出现歧义。当列表的值出现引号或空格时,就会出现歧义
语法:
for <VARIABLE> in <LIST>
do
<COMMAND>....
done
1. 从变量中读取列表值
#!/bin/bash/
city="China Japan Rassia"
for i in $city
do
echo "I'm from $i"
done
2. 从命令中取值
#!/bin/bash/
file=cityname
for i in $(cat $file)
do
echo "I'm from $i"
done
* IFS 系统默认环境变量
想更改输出情况,IFS 变量叫做内部字段分隔符,有三种形式制表符、换行符、空格
IFS=$'\n'
ps:在处理代码量较大的脚本时,可能在一个地方需要修改 IFS 的值,然后再忽略这次修改,在脚本的其他地方继续沿用 IFS 的默认值。一个可参考的安全实践是在改变 IFS 之前保存原来的 IFS 值,之后再恢复它,方法如下:
IFS.OLD=$IFS
IFS=$'\n' #在代码中使用新的 IFS 值
IFS=$IFS.OLD #这里可以参考一下利用**中间的变量**进行值互换
这就保证了在脚本的后续操作中使用的是 IFS 的默认值。如果要指定多个 IFS 字符,只要将它们在赋值行串起来就行,如下所示:
IFS=$'\n':;" #赋值会将换行符、冒号、分号和双引号作为字段分隔符
3. 使用通配符读取目录
#!/bin/bash
for file in 路径/*
do
if [ -d "$file" ]
then
echo "$file is a directory "
elif [ -f "$file" ]
then
echo "$file is a file"
fi
done
ps:1)这里注意[]的前后空格
2)if 语句判断$file 变量的类型,当类型为“-d”时,即读取到的 路径/* 内容为目录时,输出此条目为目录,
3)当类型为“-f”时,即读取到的 路径/* 内容为文件时,输出此条目为文件
4)在 Linux 中,目录名和文件名中包含空格是合法的。对于这种情况,应该将 $file 变量用双引号引起来。如果不这么做,遇到含有空格的目录名或文件名时就会有错误产生
if 语句
1. if-then
语法如下:
if command
then
commands
fi
ps:fi 是结束标志。
例:当ls命令执行成功,输出sucess
if ls
then
echo "sucess"
fi
条件比较
语法如下:
if test condition
then
commands
fi
ps:当test 命令后 condition 为空,它会以非零的退出状态码退出,并执行 else 语句块
- bash 用于整数的比较
运算符 | 含义 | 示例 |
---|---|---|
-eq | 等于 | [ "$a" -eq "$b" ] |
-ne | 不等于 | [ "$a" -ne "$b" ] |
-gt | 大于 | [ "$a" -gt "$b" ] |
-ge | 大于等于 | [ "$a" -ge "$b" ] |
-lt | 小于 | [ "$a" -lt "$b" ] |
-le | 小于等于 | [ "$a" -le "$b" ] |
- bash 字符串的比较(使用二进制运算符)
运算符 | 含义 | 示例 |
---|---|---|
= | 等于 | [ "$a" = "$b" ] |
!= | 不等于 | [ "$a" != "$b" ] |
== | 等于 | [ "$a" == "$b" ] |
- bash 测试运算符
运算符 | 含义 | 示例 |
---|---|---|
-b | 文件存在并且是块特殊 | [ -b <FILE> ] |
-c | 文件存在并且是字符特殊 | [ -c <FILE> ] |
-d | 文件存在并且是目录 | [ -d <DIRECTORY> ] |
-e | 文件存在 | [ -e <FILE> ] |
-f | 文件是常规文件 | [ -f <FILE> ] |
-L | 文件存在并且是符号链接 | [ -L <FILE> ] |
-r | 文件存在并且授予了读权限 | [ -r <FILE> ] |
-s | 文件存在并且大小大于零 | [ -s <FILE> ] |
-w | 文件存在并且授予了写权限 | [ -w <FILE> ] |
-x | 文件存在并且授予了执行权限 | [ -x <FILE> ] |
-nt | 前者比后者修改时间晚 | [ <FILE1> -nt <FILE2> ] |
-ot | 前者比后者修改时间早 | [ <FILE1> -ot <FILE2> ] |
- bash 逻辑运算符
运算符 | 含义 | 示例 |
---|---|---|
|| | 或 | [2 -gt 1] |
&& | 与 | [2 -gt 1] && [1 -gt 2];echo $? |
ps:$? 输出为0则成功
2. if-then-else
语法如下:
if command
then
commands
else
commands
fi
3. if-then-elif-then-else
语法如下:
if command
then
commands
elif
command
then
commands
else
commands
fi
4. if 嵌套语句
语法如下:
if command
then
commands
else
commands
if command
then
commands
fi
fi
while 语句
语法如下:
while test command
do
other commands
done
while 命令的关键在于所指定的 test command 的退出状态码必须随着循环中运行的命令而改变
#!/bin/bash
i=5
while [ $i -gt 0 ]
do
echo $i
i =$[ $i-1 ]
done
ps:在 while 语句中,可以在 while 命令后放入多个测试命令,只有最后一个命令的退出代码决定了 Bash Shell 是否执行已定义的 other commands。需要注意的是,每一个测试条件都要放在单独的一行中
until 语句
until test commands
do
other commands
done
和 while 语句一样,也可以在 until 语句后放入多个测试令,也是只有最后一个命令的退出代码决定了时候执行已定义的 other commands。
case 条件语句
适用于:子句太多的情况
语法:
case value in
pattern1)
commands
;;
pattern2)
commands
;;
esac
说明:case语句尝试顺序逐个将value和每个pattern,想在 case 语句中使用到类似于 else 子句的结构语句,可以在 case 语句中使用 * 作为最终模式。
#!/bin/bash
case $USER in
redhat | jack)
echo "welcom,$USER"
;;
test)
echo "the test user account"
;;
*)
echo "Sorry"
;;
esac
对于多模式操作,我们可以合并模式来共享一个操作模块,这里使用管道字符 | 来分割多个模式
嵌套循环
对于 shell 而言,它能够区分内部 for 循环和外部 while 循环各自的 do 和 done 命令
例如:
for ((a = 1;a<=3;a++))
do
echo "starting loop $a:"
for ((b=1;b<=3;b++))
do
echo " inside loop :$b"
done
done
控制循环两个命令
break 和 continue 能够帮我们控制循环的内部情况
break 命令
使用 break 可以退出任意类型的循环
#!/bin/bash
i=1
while [$i -lt 10]
do
if [$i -eq 5]
then
break
fi
echo "Iteration:$i"
i=$[ $i+1 ]
done
echo "while completed"
- break n 命令
- n 指定了要跳出循环的层级,n=1 是跳出当前的循环,终止第 n 级的外部循环
continue 命令
continue 命令可以提前终止循环
- continue n 命令
- continue n 默认 n=1,如果没有 n 表示跳过本次循环,进入下一次循环
输出结果如下
ps:注意使用continue时,这里外部循环依然继续