179 lines
4.3 KiB
Markdown
179 lines
4.3 KiB
Markdown
# 原创
|
||
: Shell流程控制:while/until 循环
|
||
|
||
# Shell流程控制:while/until 循环
|
||
|
||
### 流程控制:while/until 循环
|
||
|
||
#### while
|
||
|
||
```
|
||
#!/bin/bash
|
||
# while-count: display a series of numbers
|
||
count=1
|
||
while [ $count -le 5 ]; do
|
||
echo $count
|
||
count=$((count + 1))
|
||
done
|
||
echo "Finished."
|
||
|
||
```
|
||
|
||
优化上一节的菜单脚本:
|
||
|
||
```
|
||
#!/bin/bash
|
||
# while-menu: a menu driven system information program
|
||
DELAY=3 # Number of seconds to display results
|
||
while true; do
|
||
clear
|
||
cat <<- _EOF_
|
||
Please Select:
|
||
1. Display System Information
|
||
2. Display Disk Space
|
||
3. Display Home Space Utilization
|
||
0. Quit
|
||
_EOF_
|
||
read -p "Enter selection [0-3] > "
|
||
if [[ $REPLY =~ ^[0-3]$ ]]; then
|
||
if [[ $REPLY == 1 ]]; then
|
||
echo "Hostname: $HOSTNAME"
|
||
uptime
|
||
sleep $DELAY
|
||
continue
|
||
fi
|
||
if [[ $REPLY == 2 ]]; then
|
||
df -h
|
||
sleep $DELAY
|
||
continue
|
||
fi
|
||
if [[ $REPLY == 3 ]]; then
|
||
if [[ $(id -u) -eq 0 ]]; then
|
||
echo "Home Space Utilization (All Users)"
|
||
du -sh /home/*
|
||
else
|
||
echo "Home Space Utilization ($USER)"
|
||
du -sh $HOME
|
||
fi
|
||
sleep $DELAY
|
||
continue
|
||
fi
|
||
if [[ $REPLY == 0 ]]; then
|
||
break
|
||
fi
|
||
else
|
||
echo "Invalid entry."
|
||
sleep $DELAY
|
||
fi
|
||
done
|
||
echo "Program terminated."
|
||
|
||
```
|
||
|
||
shell中的循环支持`break和continue`
|
||
|
||
#### until
|
||
|
||
```
|
||
#!/bin/bash
|
||
# until-count: display a series of numbers
|
||
count=1
|
||
until [ $count -gt 5 ]; do
|
||
echo $count
|
||
count=$((count + 1))
|
||
done
|
||
echo "Finished."
|
||
|
||
```
|
||
|
||
### 疑难排解
|
||
|
||
```
|
||
#!/bin/bash
|
||
cd $dir_name
|
||
rm *
|
||
|
||
```
|
||
|
||
可以这样改进:`cd $dir_name && rm *`,但是有可能未设置变量 dir_name 或其变量值为空,导致删除了用户家目录下面的所有文件。`&& cd $dir_name && rm *`:
|
||
|
||
```
|
||
if [[ -d $dir_name ]]; then
|
||
if cd $dir_name; then
|
||
rm *
|
||
else
|
||
echo "cannot cd to '$dir_name'" >&2
|
||
exit 1
|
||
fi
|
||
else
|
||
echo "no such directory: '$dir_name'" >&2
|
||
exit 1
|
||
fi
|
||
|
||
```
|
||
|
||
#### 测试
|
||
|
||
早发布,常发布:如果在开发周期的早期发现 bug,那么这些 bug 就越容易定位,而且越能低成本 的修复。比喻上述删除文件的操作非常危险,所以我们可以先这样进行测试,打印出要执行的语句就行:
|
||
|
||
```
|
||
if [[ -d $dir_name ]]; then
|
||
if cd $dir_name; then
|
||
echo rm * # TESTING
|
||
else
|
||
echo "cannot cd to '$dir_name'" >&2
|
||
exit 1
|
||
fi
|
||
else
|
||
echo "no such directory: '$dir_name'" >&2
|
||
exit 1
|
||
fi
|
||
exit # TESTING
|
||
|
||
```
|
||
|
||
#### 测试案例
|
||
|
||
通过谨慎地选择输入数据或者运行边缘案例和极端案例来完成测试。比喻上述脚本,我们要测试:
|
||
1. dir_name 包含一个已经存在的目录的名字1. dir_name 包含一个不存在的目录的名字1. dir_name 为空
|
||
#### 调试
|
||
|
||
一个设计良好的脚本会对查找错误有帮助。设计良好的脚本应该具备防卫能力, 能够监测异常条件,并能为用户提供有用的反馈信息。
|
||
|
||
#### 找到问题区域
|
||
|
||
隔离脚本中与出现的问题相关的代码区域对查找问题很有帮助。 隔离的代码区域并不总是真正的错误所在,但是隔离往往可以深入了解实际的错误原因。
|
||
|
||
#### 追踪
|
||
|
||
添加提示信息追踪代码片段。把提示信息输出到标准错误输出,让其从标准输出中分离出来。bash 还提供了一种名为追踪的方法,这种方法可通过 -x 选项和 set 命令加上 -x 选项两种途径实现。
|
||
|
||
```
|
||
#!/bin/bash -x
|
||
# trouble: script to demonstrate common errors
|
||
number=1
|
||
if [ $number = 1 ]; then
|
||
echo "Number is equal to 1."
|
||
else
|
||
echo "Number is not equal to 1."
|
||
fi
|
||
|
||
or
|
||
|
||
#!/bin/bash
|
||
# trouble: script to demonstrate common errors
|
||
number=1
|
||
echo "number=$number" # DEBUG
|
||
# 为脚本中的一块选择区域,而不是整个脚本启用追踪
|
||
set -x # Turn on tracing
|
||
if [ $number = 1 ]; then
|
||
echo "Number is equal to 1."
|
||
else
|
||
echo "Number is not equal to 1."
|
||
fi
|
||
set +x # Turn off tracing
|
||
|
||
```
|
||
|
||
行首的加号表明追踪的迹象,使其与常规输出结果区分开来。使用单引号是为了防止变量展开。
|