成于坚持,败于止步
测试和分支(case与select结构)
case和select结构在技术上说并不是循环, 因为它们并不对可执行代码块进行迭代.但是和循环相似的是, 它们也依靠在代码块顶部或底部的条件判断来决定程序的分支.
case (in) / esac
在shell中的case结构与C/C++中的switch结构是相同的. 它允许通过判断来选择代码块中多条路径中的一条. 它的作用和多个if/then/else语句的作用相同,是它们的简化结构, 特别适用于创建菜单.
case "$variable" in
"$condition1" )
command...
;;
"$condition2" )
command...
;;
esac
注意四点:
1、对变量使用""并不是强制的, 因为不会发生单词分割.
2、每句测试行, 都以右小括号)来结尾.
3、每个条件判断语句块都以一对分号结尾 ;;.
4、case块以esac (case的反向拼写)结尾.
看一个实例,看看case是如何使用的
#!/bin/bash
# 测试字符串范围.
while echo; echo "Hit a key, then hit return, q(Quit)"
do
read Keypress
if [ "$Keypress" = "q" ]
then
exit 0
fi
case "$Keypress" in
[[:lower:]] ) echo "Lowercase letter";;
[[:upper:]] ) echo "Uppercase letter";;
[0-9] ) echo "Digit";;
* ) echo "Punctuation, whitespace, or other";;
esac # 允许字符串的范围出现在[中括号]中,
#+ 或者出现在POSIX风格的[[双中括号中.
done
# 在这个例子的第一个版本中,
#+ 测试大写和小写字符串的工作使用的是
#+ [a-z] 和 [A-Z].
# 这种用法在某些特定场合的或某些Linux发行版中不能够正常工作.
# POSIX 的风格更具可移植性.
# 感谢Frank Wang指出了这点.
exit 0
结果:
root@ubuntu:~/resource/shell-study/0613-2013# ./test4.sh
Hit a key, then hit return, q(Quit)
w
Lowercase letter
Hit a key, then hit return, q(Quit)
1
Digit
Hit a key, then hit return, q(Quit)
E
Uppercase letter
Hit a key, then hit return, q(Quit)
q
root@ubuntu:~/resource/shell-study/0613-2013#
接着看一个例子,使用case来创建菜单:
#!/bin/bash
clear # 清屏.
echo " Contact List"
echo " ------- ----"
echo "Choose one of the following persons:"
echo
echo "[E]vans, Roland"
echo "[J]ones, Mildred"
echo "[w]yu, Wang"
echo
read person
for para in $person
do
case "$para" 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 "[email protected]"
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 "[email protected]"
echo "Ex-girlfriend"
echo "Birthday: Feb. 11"
;;
"W" | "w" )
echo
echo "yu wang"
echo "1987-07-30"
echo "New York, NY 10009"
echo "(212) 533-2814"
echo "(212) 533-9972 fax"
echo "[email protected]"
echo "Ex-girlfriend"
;;
* )
# 默认选项.
# 空输入(敲回车RETURN), 也适用于这里.
echo
echo "Not yet in database."
;;
esac
done
echo
exit 0
结果:
Contact List
------- ----
Choose one of the following persons:
[E]vans, Roland
[J]ones, Mildred
[w]yu, Wang
j w
Mildred Jones
249 E. 7th St., Apt. 19
New York, NY 10009
(212) 533-2814
(212) 533-9972 fax
[email protected]
Ex-girlfriend
Birthday: Feb. 11
yu wang
1987-07-30
New York, NY 10009
(212) 533-2814
(212) 533-9972 fax
[email protected]
Ex-girlfriend
root@ubuntu:~/resource/shell-study/0613-2013#
上面两个实例同时使用了while和for循环的方式对书中代码进行了少许修改,书中给了个很聪明的实例,那就一定要看看了,O(∩_∩)O~
#! /bin/bash
case "$1" in
"") # 没有命令行参数,或者第一个参数为空.
echo "Usage: ${0##*/} "
exit $E_PARAM
;;
# 注意: ${0##*/} 是 ${var##pattern} 的一种替换形式. 得到的结果为$0.
-*)
FILENAME=./$1 # 如果传递进来的文件名参数($1)以一个破折号开头,
#+ 那么用./$1来代替.
#+ 这样后边的命令将不会把它作为一个选项来解释.
echo $FILENAME
;;
* )
FILENAME=$1 # 否则, $1.
echo $FILENAME
;;
esac
结果:
root@ubuntu:~/resource/shell-study/0613-2013# ./test6.sh test1.sh
test1.sh
root@ubuntu:~/resource/shell-study/0613-2013# ./test6.sh -ehello
./-ehello
root@ubuntu:~/resource/shell-study/0613-2013#
不过呢,可能你并不理解,这个脚本到底聪明在哪里,要理解这个程序,你首先看一下下面的过程:
root@ubuntu:~/resource/shell-study/0613-2013# touch -ehello
touch: invalid option -- 'e'
Try `touch --help' for more information.
root@ubuntu:~/resource/shell-study/0613-2013# ls
nested-loop.sh test1.sh test2.sh test3.sh test4.sh test5.sh test6.sh
root@ubuntu:~/resource/shell-study/0613-2013# touch ./-ehello
root@ubuntu:~/resource/shell-study/0613-2013# ls
-ehello nested-loop.sh test1.sh test2.sh test3.sh test4.sh test5.sh test6.sh
可以看到,当我使用touch -ehello去新建一个名叫“-ehello”的空文件时,提示错误,因为默认把-后面的字符解析为命令,要想避免shell把-解析为命令,就需要使用下面的第二种方式,touch ./-ehello,所以现在可以看出这个脚本的聪明之处了吧,放在把以“-”开头的文件名解析为命令
还有一个一个命令行参数处理的更容易理解的例子:
#! /bin/bash
while [ $# -gt 0 ]; do # 直到你用完所有的参数 . . .
case "$1" in
-d|--debug)
# 是 "-d" 或 "--debug" 参数?
DEBUG=1
echo "open the debug mode"
;;
-c|--conf)
CONFFILE="$2"
shift
if [ ! -f $CONFFILE ]; then
echo "Error: Supplied file doesn't exist!"
exit $E_CONFFILE # 错误: 文件未发现.
else
echo "command: -c $CONFFILE"
fi
;;
esac
shift # 检查剩余的参数.
done
结果:
root@ubuntu:~/resource/shell-study/0613-2013# ./test7.sh -d
open the debug mode
root@ubuntu:~/resource/shell-study/0613-2013# ./test7.sh -c test1.sh
command: -c test1.sh
root@ubuntu:~/resource/shell-study/0613-2013#
使用命令替换来产生case变量
#!/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
结果:
root@ubuntu:~/resource/shell-study/0613-2013# chmod +x test8.sh
root@ubuntu:~/resource/shell-study/0613-2013# ./test8.sh
Pentium2+-based machine
root@ubuntu:~/resource/shell-study/0613-2013#
简单的字符串匹配
#!/bin/bash
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
结果:
root@ubuntu:~/resource/shell-study/0613-2013# chmod +x test9.sh
root@ubuntu:~/resource/shell-study/0613-2013# ./test9.sh
91
90
0
root@ubuntu:~/resource/shell-study/0613-2013#
检查输入字符是否为字母
#!/bin/bash
# isalpha.sh: 使用"case"结构来过滤字符串.
SUCCESS=0
FAILURE=-1
isalpha () # 检查输入的 *第一个字符* 是不是字母表上的字符.
{
if [ -z "$1" ] # 没有参数传进来?
then
return $FAILURE
fi
case "$1" in
[a-zA-Z]*) return $SUCCESS;; # 以一个字母开头?
* ) return $FAILURE;;
esac
} # 同C语言的"isalpha ()"函数比较一下.
isalpha2 () # 测试 *整个字符串* 是否都是字母表上的字符.
{
[ $# -eq 1 ] || return $FAILURE
case $1 in
*[!a-zA-Z]*|"") return $FAILURE;;
*) return $SUCCESS;;
esac
}
isdigit () # 测试 *整个字符串* 是否都是数字.
{ # 换句话说, 就是测试一下是否是整数变量.
[ $# -eq 1 ] || return $FAILURE
case $1 in
*[!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 [0 - 9]."
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改进了这个脚本.
结果:
root@ubuntu:~/resource/shell-study/0613-2013# chmod +x test10.sh
root@ubuntu:~/resource/shell-study/0613-2013# ./test10.sh
./test10.sh: line 16: return: -1: invalid option
return: usage: return [n]
"23skidoo" begins with a non-alpha character.
"H3llo" begins with an alpha character.
./test10.sh: line 26: return: -1: invalid option
return: usage: return [n]
"H3llo" contains at least one non-alpha character.
./test10.sh: line 16: return: -1: invalid option
return: usage: return [n]
"-What?" begins with a non-alpha character.
"What?" begins with an alpha character.
./test10.sh: line 26: return: -1: invalid option
return: usage: return [n]
"What?" contains at least one non-alpha character.
"H3llo" begins with an alpha character.
./test10.sh: line 26: return: -1: invalid option
return: usage: return [n]
"H3llo" contains at least one non-alpha character.
"AbcDef" begins with an alpha character.
"AbcDef" contains only alpha characters.
./test10.sh: line 11: return: -1: invalid option
return: usage: return [n]
./test10.sh: line 16: return: -1: invalid option
return: usage: return [n]
"" begins with a non-alpha character.
"27234" contains only digits [0 - 9].
./test10.sh: line 36: return: -1: invalid option
return: usage: return [n]
"27a34" has at least one non-digit character.
./test10.sh: line 36: return: -1: invalid option
return: usage: return [n]
"27.34" has at least one non-digit character.
root@ubuntu:~/resource/shell-study/0613-2013#
select结构是建立菜单的另一种工具, 这种结构是从ksh中引入的.
select variable [in list]
do
command...
break
done
提示用户输入选择的内容(比如放在变量列表中),注意: select命令使用PS3提示符, 默认为(\#?), 当然, 这可以修改.
#!/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
结果:
root@ubuntu:~/resource/shell-study/0613-2013# chmod +x test11.sh
root@ubuntu:~/resource/shell-study/0613-2013# ./test11.sh
1) beans
2) carrots
3) potatoes
4) onions
5) rutabagas
Choose your favorite vegetable: 2
Your favorite veggie is carrots.
Yuck!
root@ubuntu:~/resource/shell-study/0613-2013#
如果注释掉其中的break,结果也许会出于你的意料吧:
#!/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
结果:
root@ubuntu:~/resource/shell-study/0613-2013# ./test11.sh
1) beans
2) carrots
3) potatoes
4) onions
5) rutabagas
Choose your favorite vegetable: 1
Your favorite veggie is beans.
Yuck!
Choose your favorite vegetable: 2
Your favorite veggie is carrots.
Yuck!
Choose your favorite vegetable: 3
Your favorite veggie is potatoes.
Yuck!
Choose your favorite vegetable: 4
Your favorite veggie is onions.
Yuck!
Choose your favorite vegetable: 5
Your favorite veggie is rutabagas.
Yuck!
Choose your favorite vegetable: ^C
root@ubuntu:~/resource/shell-study/0613-2013#
直到你使用ctrl+c才会退出
如果忽略了in list列表, 那么select命令将会使用传递到脚本的命令行参数(\$@), 或者是函数参数(当select是在函数中时).
与忽略in list的for variable [in list]结构比较一下.
#!/bin/bash
PS3='Choose your favorite vegetable: '
echo
choice_of()
{
select vegetable
# [in list]被忽略, 所以'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
结果:
root@ubuntu:~/resource/shell-study/0613-2013# chmod +x test112.sh
root@ubuntu:~/resource/shell-study/0613-2013# ./test112.sh
1) beans
2) rice
3) carrots
4) radishes
5) tomatoes
6) spinach
Choose your favorite vegetable: 2
Your favorite veggie is rice.
Yuck!
root@ubuntu:~/resource/shell-study/0613-2013#
分支用法就说到这里
先到这里了,O(∩_∩)O~
我的专栏地址:http://blog.csdn.net/column/details/shell-daily-study.html
待续。。。。。