本章节继续介绍流程控制语句,在前面的while语句,read语句生成了一些简单的菜单并构建了用户选择处理逻辑。使用了了一系列的if命令来识别可能的菜单选项。这种逻辑经常会出现在程序中,Shell提供了们处理多重选择的流程控制机制。
1.case命令
在Bash中,多重选择复合命令是case,用法如下:
case word in[parrern [| pattern]...) commands ;;]...
esac
使用case简化用户选择处理逻辑:
[sysadmin@ansible bin]$ cat case-menu
#!/bin/bash#case-menuclear
echo "
Please Select:1.Display System Information
2.Display Disk Space
3.Display Home Space Utilization
4.Quit
"
read -p "Enter selection [0-3] > "case "$REPLY" in0) echo "Program terminated."exit;;1) echo "Hostname: $HOSTNAME"uptime;;2) df -h;;3) if [[ "$(id -u)" -eq 0 ]]; thenecho "Home Space Utilization (ALL Users)"du -sh /home/*elseecho "Home Space Utilizaion ($USER)"du -sh "$HOME"fi;;*) echo "Invalid entry." >&2exit 1;;
esac
case命令查看word的值,本例中就是REPLY的值,然后将其与patterns指定的模式匹配。如果找到匹配,则执行与该模式关联的命令,之后不再尝试进行其他匹配。
1.1 模式
case使用的模式与路径名扩展使用的模式一样,模式以)结尾。下表描述了case模式示例:
模式 | 描述 |
---|---|
a) | 如果word是a,则匹配 |
[[:alpha:]] | 如果word是单个字母,则匹配 |
???) | 如果word是3个字符,则匹配 |
*.txt) | 如果word是以.txt结尾,则匹配 |
*) | 不管word是什么内容,均可匹配。将该模式作为case命令最后一个模式是一种不错的做法,可以匹配之前的模式无法匹配到的内容,也就是说,能捕获到所有的“漏网之鱼” |
[sysadmin@ansible bin]$ cat case-sample
#!/bin/bash# case-sampleread -p "enter word > "case "$REPLY" in[[:alpha:]]) echo ""$REPLY" is a single alphabetic character." ;;[ABC][0-9]) echo ""$REPLY" is A, B, or C followed by a digit." ;;???) echo ""$REPLY" is three characters long." ;;*.txt) echo ""$REPLY" is a word ending in '*.txt'" ;;*) echo ""$REPLY" is something else." ;;
esac
也可以使用|作为分隔符,将多个模式组合在一起,形成“逻辑或”(or)关系的条件模式,这在同时处理大小写字母的的时候很有用。
[sysadmin@ansible bin]$ cat case-menu
#!/bin/bash#case-menuclear
echo "
Please Select:B.Display System Information
C.Display Disk Space
D.Display Home Space Utilization
Q.Quit
"
read -p "Enter selection [0-3] > "case "$REPLY" inq|Q) echo "Program terminated."exit;;b|B) echo "Hostname: $HOSTNAME"uptime;;c|C) df -h;;d|D) if [[ "$(id -u)" -eq 0 ]]; thenecho "Home Space Utilization (ALL Users)"du -sh /home/*elseecho "Home Space Utilizaion ($USER)"du -sh "$HOME"fi;;*) echo "Invalid entry." >&2exit 1;;
esac
1.2 执行多次操作
Bash之前,case只允许在成功的匹配分支上执行一次操作,操作结束后,case命令随之终止。来看一个字符匹配脚本:
[sysadmin@ansible bin]$ cat case-1
#!/bin/bash# case-1:测试一个字符read -n 1 -p "Type a character > "
echocase "$REPLY" in[[:upper:]]) echo "$REPLY is a upper case." ;;[[:lower:]]) echo "$REPLY is a lower case." ;;[[:alpha:]]) echo "$REPLY is a alphabetic." ;;[[:digit:]]) echo "$REPLY is a digit." ;;[[:graph:]]) echo "$REPLY is a visible character." ;;[[:punct:]]) echo "$REPLY is a punctuation symbol." ;;[[:space:]]) echo "$REPLY is a whitespace character." ;;[[:xdigit:]]) echo "$REPLY is a hexadecimal digit." ;;
esac
在Bash4.0之前,case无法匹配多个分支。现代版本的Bash添加了;;&语法,允许继续测试下一个模式,上一个代码改写为
[sysadmin@ansible bin]$ cat case-2
#!/bin/bash# case-2:测试多个字符read -n 1 -p "Type a character > "
echocase "$REPLY" in[[:upper:]]) echo "$REPLY is a upper case." ;;&[[:lower:]]) echo "$REPLY is a lower case." ;;&[[:alpha:]]) echo "$REPLY is a alphabetic." ;;&[[:digit:]]) echo "$REPLY is a digit." ;;&[[:graph:]]) echo "$REPLY is a visible character." ;;&[[:punct:]]) echo "$REPLY is a punctuation symbol." ;;&[[:space:]]) echo "$REPLY is a whitespace character." ;;&[[:xdigit:]]) echo "$REPLY is a hexadecimal digit." ;;&
esac
[sysadmin@ansible bin]$ case-2
Type a character > a
a is a lower case.
a is a alphabetic.
a is a visible character.
a is a hexadecimal digit.
[sysadmin@ansible bin]$
有了;;&,case就可以继续测试模式,而不再直接终止。case是处理某些特定类型问题的绝佳工具。