shell case-Bad
支(case与select结构)case和select结构在技术上说并不是循环, 因为它们并不对可执行代码块进行迭代. 但是和循环相似的是, 它们也依靠在代码块顶部或底部的条件判断来决定程序的分支.
在代码块中控制程序分支
case (in) / esac
在shell中的case结构与C/C++中的switch结构是相同的. 它允许通过判断来选择代码块中多条路径中的一条. 它的作用和多个if/then/else语句的作用相同, 是它们的简化结构, 特别适用于创建菜单.
Ruby代码http://hlee.iteye.com/images/icon_star.png
[*] case"$variable"in
[*] "$condition1" )
[*] command...
[*] ;;
[*] "$condition2" )
[*] command...
[*] ;;
[*] esac
[*] Note
*
对变量使用""并不是强制的, 因为不会发生单词分割.
*
每句测试行, 都以右小括号)来结尾.
*
每个条件判断语句块都以一对分号结尾 ;;.
*
case块以esac (case的反向拼写)结尾.
例子 10-24. 使用case
Ruby代码http://hlee.iteye.com/images/icon_star.png
[*] #!/bin/bash
[*] # 测试字符串范围.
[*] echo; echo "Hit a key, then hit return."
[*] read Keypress
[*] case"$Keypress"in
[*] [[:lower:]] ) echo "Lowercase letter";;
[*] [[:upper:]] ) echo "Uppercase letter";;
[*] ) echo "Digit";;
[*] * ) echo "Punctuation, whitespace, or other";;
[*] esac #允许字符串的范围出现在[中括号]中,
[*] #+ 或者出现在POSIX风格的[[双中括号中.
[*] #在这个例子的第一个版本中,
[*] #+ 测试大写和小写字符串的工作使用的是
[*] #+ 和 .
[*] #这种用法在某些特定场合的或某些Linux发行版中不能够正常工作.
[*] #POSIX 的风格更具可移植性.
[*] #感谢Frank Wang指出了这点.
[*] #练习:
[*] #-----
[*] #就像这个脚本所表现出来的, 它只允许单次的按键, 然后就结束了.
[*] #修改这个脚本, 让它能够接受重复输入,
[*] #+ 报告每次按键, 并且只有在"X"被键入时才结束.
[*] #暗示: 将这些代码都用"while"循环圈起来.
[*] exit 0
例子 10-25. 使用case来创建菜单
Ruby代码http://hlee.iteye.com/images/icon_star.png
[*] #!/bin/bash
[*] # 未经处理的地址资料
[*] clear # 清屏.
[*] echo " Contact List"
[*] echo " ------- ----"
[*] echo "Choose one of the following persons:"
[*] echo
[*] echo "vans, Roland"
[*] echo "ones, Mildred"
[*] echo "mith, Julie"
[*] echo "ane, Morris"
[*] echo
[*] read person
[*] case"$person"in
[*] # 注意, 变量是被""引用的.
[*] "E" | "e" )
[*] # 接受大写或者小写输入.
[*] echo
[*] echo "Roland Evans"
[*] echo "4321 Floppy Dr."
[*] echo "Hardscrabble, CO 80753"
[*] echo "(303) 734-9874"
[*] echo "(303) 734-9892 fax"
[*] echo "revans@zzy.net"
[*] echo "Business partner & old friend"
[*] ;;
[*] # 注意, 每个选项后边都要以双分号;;结尾.
[*] "J" | "j" )
[*] echo
[*] echo "Mildred Jones"
[*] echo "249 E. 7th St., Apt. 19"
[*] echo "New York, NY 10009"
[*] echo "(212) 533-2814"
[*] echo "(212) 533-9972 fax"
[*] echo "milliej@loisaida.com"
[*] echo "Ex-girlfriend"
[*] echo "Birthday: Feb. 11"
[*] ;;
[*] # 后边的 Smith 和 Zane 的信息在这里就省略了.
[*] * )
[*] # 默认选项.
[*] # 空输入(敲回车RETURN), 也适用于这里.
[*] echo
[*] echo "Not yet in database."
[*] ;;
[*] esac
[*] echo
[*] #练习:
[*] #-----
[*] #修改这个脚本, 让它能够接受多个输入,
[*] #+ 并且能够显示多个地址.
[*] exit 0
一个case的非常聪明的用法, 用来测试命令行参数.
Ruby代码http://hlee.iteye.com/images/icon_star.png
[*] #! /bin/bash
[*] case"$1"in
[*] "") echo "Usage: ${0##*/} "; exit $E_PARAM;;# 没有命令行参数,
[*] # 或者第一个参数为空.
[*] # 注意: ${0##*/} 是 ${var##pattern} 的一种替换形式. 得到的结果为$0.
[*] -*) FILENAME=./$1;; #如果传递进来的文件名参数($1)以一个破折号开头,
[*] #+ 那么用./$1来代替.
[*] #+ 这样后边的命令将不会把它作为一个选项来解释.
[*] * ) FILENAME=$1;; # 否则, $1.
[*] esac
这是一个命令行参数处理的更容易理解的例子:
Ruby代码http://hlee.iteye.com/images/icon_star.png
[*] #! /bin/bash
[*] while [ $# -gt 0 ]; do # 直到你用完所有的参数 . . .
[*] case"$1"in
[*] -d|--debug)
[*] # 是 "-d" 或 "--debug" 参数?
[*] DEBUG=1
[*] ;;
[*] -c|--conf)
[*] CONFFILE="$2"
[*] shift
[*] if [ ! -f $CONFFILE ]; then
[*] echo "Error: Supplied file doesn't exist!"
[*] exit $E_CONFFILE# 错误: 文件未发现.
[*] fi
[*] ;;
[*] esac
[*] shift # 检查剩余的参数.
[*] done
[*] #来自Stefano Falsetto的 "Log2Rot" 脚本,
[*] #+ 并且是他的"rottlog"包的一部分.
[*] #已得到使用许可.
例子 10-26. 使用命令替换来产生case变量
Ruby代码http://hlee.iteye.com/images/icon_star.png
[*] #!/bin/bash
[*] # case-cmd.sh: 使用命令替换来产生"case"变量.
[*] case $( arch ) in# "arch" 返回机器体系的类型.
[*] # 等价于 'uname -m' ...
[*] i386 ) echo "80386-based machine";;
[*] i486 ) echo "80486-based machine";;
[*] i586 ) echo "Pentium-based machine";;
[*] i686 ) echo "Pentium2+-based machine";;
[*] * ) echo "Other type of machine";;
[*] esac
[*] exit 0
case结构也可以过滤通配(globbing)模式的字符串.
例子 10-27. 简单的字符串匹配
Ruby代码http://hlee.iteye.com/images/icon_star.png
[*] #!/bin/bash
[*] # match-string.sh: 简单的字符串匹配
[*] match_string ()
[*] {
[*] MATCH=0
[*] NOMATCH=90
[*] PARAMS=2 # 此函数需要2个参数.
[*] BAD_PARAMS=91
[*] [ $# -eq $PARAMS ] || return $BAD_PARAMS
[*] case"$1"in
[*] "$2") return$MATCH;;
[*] * ) return$NOMATCH;;
[*] esac
[*] }
[*] a=one
[*] b=two
[*] c=three
[*] d=two
[*] match_string $a# 参数个数错误.
[*] echo $? # 91
[*] match_string $a$b# 不匹配
[*] echo $? # 90
[*] match_string $b$d# 匹配
[*] echo $? # 0
[*] exit 0
例子 10-28. 检查输入字符是否为字母
Ruby代码http://hlee.iteye.com/images/icon_star.png
[*] #!/bin/bash
[*] # isalpha.sh: 使用"case"结构来过滤字符串.
[*] SUCCESS=0
[*] FAILURE=-1
[*] isalpha ()# 检查输入的 *第一个字符* 是不是字母表上的字符.
[*] {
[*] if [ -z "$1" ] # 没有参数传进来?
[*] then
[*] return$FAILURE
[*] fi
[*] case"$1"in
[*] *) return$SUCCESS;;# 以一个字母开头?
[*] * ) return$FAILURE;;
[*] esac
[*] } # 同C语言的"isalpha ()"函数比较一下.
[*] isalpha2 () # 测试 *整个字符串* 是否都是字母表上的字符.
[*] {
[*] [ $# -eq 1 ] || return $FAILURE
[*] case$1in
[*] *[!a-zA-Z]*|"") return$FAILURE;;
[*] *) return$SUCCESS;;
[*] esac
[*] }
[*] isdigit () # 测试 *整个字符串* 是否都是数字.
[*] { # 换句话说, 就是测试一下是否是整数变量.
[*] [ $# -eq 1 ] || return $FAILURE
[*] case$1in
[*] *[!0-9]*|"") return$FAILURE;;
[*] *) return$SUCCESS;;
[*] esac
[*] }
[*] check_var ()# 测试isalpha().
[*] {
[*] if isalpha "$@"
[*] then
[*] echo "\"$*\" begins with an alpha character."
[*] if isalpha2 "$@"
[*] then# 不需要测试第一个字符是否是non-alpha.
[*] echo "\"$*\" contains only alpha characters."
[*] else
[*] echo "\"$*\" contains at least one non-alpha character."
[*] fi
[*] else
[*] echo "\"$*\" begins with a non-alpha character."
[*] # 如果没有参数传递进来, 也是"non-alpha".
[*] fi
[*] echo
[*] }
[*] digit_check ()# 测试isdigit().
[*] {
[*] if isdigit "$@"
[*] then
[*] echo "\"$*\" contains only digits ."
[*] else
[*] echo "\"$*\" has at least one non-digit character."
[*] fi
[*] echo
[*] }
[*] a=23skidoo
[*] b=H3llo
[*] c=-What?
[*] d=What?
[*] e=`echo $b` # 命令替换.
[*] f=AbcDef
[*] g=27234
[*] h=27a34
[*] i=27.34
[*] check_var $a
[*] check_var $b
[*] check_var $c
[*] check_var $d
[*] check_var $e
[*] check_var $f
[*] check_var # 没有参数传递进来, 将会发生什么?
[*] #
[*] digit_check $g
[*] digit_check $h
[*] digit_check $i
[*] exit 0 # S.C改进了这个脚本.
# 练习:
# -----
#编写一个'isfloat ()'函数来测试浮点数.
#暗示: 这个函数基本上与'isdigit ()'相同,
#+ 但是要添加一些小数点部分的处理.
select
select结构是建立菜单的另一种工具, 这种结构是从ksh中引入的.
select variable
do
command...
燽reak
done
提示用户输入选择的内容(比如放在变量列表中). 注意: select命令使用PS3提示符, 默认为(#?), 当然, 这可以修改.
例子 10-29. 使用select来创建菜单
Ruby代码http://hlee.iteye.com/images/icon_star.png
[*] #!/bin/bash
[*] PS3='Choose your favorite vegetable: '# 设置提示符字串.
[*] echo
[*] select vegetable in"beans""carrots""potatoes""onions""rutabagas"
[*] do
[*] echo
[*] echo "Your favorite veggie is $vegetable."
[*] echo "Yuck!"
[*] echo
[*] break# 如果这里没有 'break' 会发生什么?
[*] done
[*] exit 0
如果忽略了in list列表, 那么select命令将会使用传递到脚本的命令行参数($@), 或者是函数参数(当select是在函数中时).
与忽略in list的
for variable
结构比较一下.
例子 10-30. 使用函数中的select结构来创建菜单
Ruby代码http://hlee.iteye.com/images/icon_star.png
[*] #!/bin/bash
[*] PS3='Choose your favorite vegetable: '
[*] echo
[*] choice_of()
[*] {
[*] select vegetable
[*] # 被忽略, 所以'select'使用传递给函数的参数.
[*] do
[*] echo
[*] echo "Your favorite veggie is $vegetable."
[*] echo "Yuck!"
[*] echo
[*] break
[*] done
[*] }
[*] choice_of beans rice carrots radishes tomatoes spinach
[*] # $1 $2 $3 $4 $5 $6
[*] # 传递给choice_of()的参数
[*] exit 0
页:
[1]