bash脚本编程:
case选择分支结构:
case: case 词 in [模式 [| 模式]...) 命令 ;;]... esac
在脚本中使用case的结构:
case ${VAR_NAME} in
PATTERN1)
COMMAND
...
;;
PATTERN2)
COMMAND
...
;;
...
esac
扩展:
case ${VAR_NAME} in
PATTERN1)
COMMAND
...
;;
PATTERN2)
COMMAND
...
;;
*) //‘*)’在这里是如果不是模式1也不是模式2时,就使用‘*)’后的命令
COMMAND
...
;;
esac
PATTERN(模式)可以是下列几类字符:
1.普通文本字符
2.Globbing风格的通配符
*:任意长度的任意字符
?:任意单个字符
[]:指定范围内的任意单个字符
[^]:指定范围外的任意单个字符
3.| 或字符,实现‘或’操作
写一个脚本:
判断用户利用脚本删除文件时,是否执行删除操作;
#!/bin/bash
#判断用户利用脚本删除文件时,是否执行删除操作(case选择分支结构);
#判断用户是否存在,存在就执行是否删除文件的操作,不存在就显示文件不存在;
if [ -a $1 ];then
echo -e "\033[5;1;32mDanger!\033[1;31mAre you sure to delete it ? [ yes or no ] \033[0m"
#与用户交互使用read命令,-t选项显示5秒
read -t 5 CHOICE
#检测CHOICE的值是否存在,如果不存在就默认显示为no
[ -z $CHOICE ] && CHOICE=no
#case选择分支结构,如果$CHOICE的值是yes就执行删除命令,no则显示"Right choice."
case $CHOICE in
yes)
rm -rf $1
;;
no)
echo "Right choice."
;;
esac
else
echo "$1 does not exist."
fi
#回收变量
unset CHOICE
#!/bin/bash
#判断用户利用脚本删除文件时,是否执行删除操作(if循环结构);
#判断用户是否存在,存在就执行是否删除文件的操作,不存在就显示文件不存在;
if [ -e $1 ] ; then
echo -e "\033[5;1;31mDanger!\033[0m\033[1;31mAre you sure to delete it? [yes or no] \033[0m"
#与用户交互使用read命令,-t选项显示5秒
read -t 5 CHOICE
#检测CHOICE的值是否存在,如果不存在就默认显示为no
[ -z $CHOICE ] && CHOICE=no
#if多分支执行结构,如果是yes就执行删除命令,no则显示"Right choice."
if [ "$CHOICE" == 'yes' ] ; then
rm -rf $1
elif [ "$CHOICE" == 'no' ] ; then
echo "Right choice."
fi
else
echo "$1 does not exist."
fi
#回收变量
unset CHOICE
if的多分支结构和case的选择分支结构的异同:
相同点:
1.判断的条件为真时,才会执行对应分支中的语句命令;条件为假跳过不执行;
2.都可以设置默认分支语句,即所有给定的条件都为假时才会执行的语句。
不同点:
1.if是根据命令的执行状态返回值的真或假是否该执行某个分支中的语句;case一般是根据变量中所保存的值与指定的模式匹配的结果的真或假来判断是否执行某个分支中的语句;
2.if的每个分支中无须单独的结束标记,case的每个分支都必须以‘;;’结束;
示例:
设置编写管理用户账户的脚本,利用case语句+for循环,同时接受创建用户和删除用户的操作:
#!/bin/bash
#设置编写管理用户账户的脚本,利用case语句+for循环,同时接受创建用户和删除用户的操作:
#设置用户给定的参数值至少要有1个,否则输出如下的信息,返回值为5;
if [ $# -lt 1 ] ; then
echo -e "Usage: $(basename $0) options... USERLIST\n"
echo -e " Options: "
echo -e " -a, --add: \vAdd some users from USERLIST."
echo -e " -d, --delete: \vDelete some users from USERLIST."
echo -e " -h, --help: \vPrint help informationn."
echo -e " -v, --verbose: \vPrint more informationn about manage users."
echo
echo -e " USERLIST FORMAT: "
echo -e " USERNAME1,USERNAME2,...,USERNAMEN"
exit 5
fi
#定义三个开关量,当0变为1的时候,说明就有这个操作了;
ADDUSER=0
DELUSER=0
DEBUG=0
#有多少个参数就执行for循环多少次,
for I in $(seq $#) ; do
#如果参数不为0,就利用case结构执行判断用户给定的第一个参数的内容,如果给定的内容不在case设定的范围内,就输出帮助文档;
if [ $# -ne 0 ] ;then
case $1 in
-h|--help)
echo -e "Usage: $(basename $0) options... USERLIST\n"
echo -e " Options: "
echo -e " -a, --add: \vAdd some users from USERLIST"
echo -e " -d, --delete: \vDelete some users from USERLIST"
echo -e " -h, --help: \vPrint help informationn"
echo -e " -v, --verbose: \vPrint more informationn about manage users."
echo
echo -e " USERLIST FORMAT: "
echo -e " USERNAME1,USERNAME2,...,USERNAMEN"
#如果用户输入-h选项,返回值就为0,表明之后的命令不会再执行;
exit 0
;;
-v|--verbose)
#当DEBUG为1的时候就显示之后的信息;
DEBUG=1
#把-v选项shift掉;
shift
;;
-a|--add)
ADDUSERLIST=$2
ADDUSER=1
shift 2
;;
-d|--delete)
DELUSERLIST=$2
DELUSER=1
shift 2
;;
*)
echo -e "Usage: $(basename $0) options... USERLIST\n"
echo -e " Options: "
echo -e " -a, --add: \vAdd some users from USERLIST"
echo -e " -d, --delete: \vDelete some users from USERLIST"
echo -e " -h, --help: \vPrint help informationn"
echo -e " -v, --verbose: \vPrint more informationn about manage users."
echo
echo -e " USERLIST FORMAT: "
echo -e " USERNAME1,USERNAME2,...,USERNAMEN"
exit 6
;;
esac
fi
done
#如果$ADDUSER等于1,证明我们添加了-a选项,进而执行之后的命令;
if [ $ADDUSER -eq 1 ] ; then
#利用for循环,添加多个用户,多个用户之间用“,”分隔,为了更好的执行命令,在这里用空格代替“,”从而实现添加多个用户的操作;
for J in $(echo $ADDUSERLIST | tr ',' ' ') ; do
#在添加用户之前,首先要确定用户的存在,如果用户不存在就添加用户,存在就输出用户已存在;
if ! id $J &> /dev/null ; then
useradd $J &> /dev/null
echo $J | passwd --stdin $J &> /dev/null
#当DEBUG为1的时候就显示之后的信息,意味着添加了-v选项;
[ $DEBUG -eq 1 ] && echo "Create user $J successfully."
else
echo "$J exist already."
fi
done
fi
#如果$DELUSER等于1,证明我们添加了-d选项,进而执行之后的命令;
if [ $DELUSER -eq 1 ] ; then
#利用for循环,删除多个用户,多个用户之间用“,”分隔,为了更好的执行命令,在这里用空格代替“,”从而实现删除多个用户的操作;
for J in $(echo $DELUSERLIST | tr ',' ' ') ; do
#在删除用户之前,首先要确定用户的存在,如果用户已经存在就删除用户,否则显示用户不存在;
if id $J &> /dev/null ; then
userdel -r $J &> /dev/null
#当DEBUG为1的时候就显示之后的信息,意味着添加了-v选项;
[ $DEBUG -eq 1 ] && echo "Delete user $J finished."
else
echo "$J does not exist yet."
fi
done
fi
#记得回收内存空间
unset ADDUSER DELUSER DEBUG I J
while循环结构:
while: while 命令; do 命令; done
在脚本中可以写成下列结构:
while CONDITION ;do
COMMANDS
done
while循环进入循环的条件:CONDITION逻辑判断结果为真;
while循环退出循环的条件:CONDITION逻辑判断结果为假;
until循环结构:
until: until 命令; do 命令; done
在脚本中可以写成下列结构:
until CONDITION ;do
COMMANDS
done
until循环进入循环的条件:CONDITION逻辑判断结果为假;
until循环退出循环的条件:CONDITION逻辑判断结果为真;
注意:
1.while CONDITION 相当于 until ! CONDITION
2.while和until循环结构中,没有变量自增或自减的变化方法,因此需要使用语句手动给出变量的变化方式;
例子:
写一个脚本:使用while或until循环,计算100以内的整数和
#!/bin/bash
#until循环
#定义I初值为0
declare -i I=0
#当I的值小于等于100的时候执行累加和命令,直到I的值大于100的时候就结束循环;
until [ $I -gt 100 ];do
let SUM+=$I
let I++
done
#输出累加结果;
echo $SUM
#while循环
#定义J的初值为0
declare -i J=0
#当J的值小于等于100时执行累加命令,当J的值超出100时结束当前循环;
while [ $J -le 100 ];do
let SUM1+=$J
let J++
done
#输出累加结果;
echo -e "\n$SUM1"
#别忘了回收变量,浪费内存空间是不好的哦!
unset I J SUM SUM1
循环控制语句:
continue: continue [n]
继续 for、while、或 until 循环。 提前结束第n层当前循环,直接进入下一轮条件判断,如果条件判断结果仍然满足循环进入条件,则开启下一轮循环;
继续当前 FOR、WHILE 或 UNTIL 循环的下一步。
如果指定了 N, 则继续当前的第 N 重循环。
退出状态:
退出状态为 0 除非 N 不大于或等于1。
示例:
计算100以内奇数和;
#!/bin/bash
#定义I初值为0
declare -i I=0
while [ $I -le 100 ];do
#如果I的值取模后的值等于0就加1,如果不等于就跳过直接执行下一轮的命令
if [ $[I%2] -eq 0 ];then
let I++
continue
fi
let SUM+=$I
let I++
done
#别忘了回收变量,浪费内存空间是不好的哦!
unset I SUM
echo $SUM
break: break [n]
退出 for、while、或 until 循环
提前结束第n层循环,而且不再进行后续循环;
退出一个 FOR、WHILE 或 UNTIL 循环。如果指定了N,则打破N重
循环
退出状态:
退出状态为0除非 N 不大于或等于 1。
while和until的两种特殊循环方法:
1.无限循环方法:
while true ; do
COMMANDS
done
until false ; do
COMMANDS
done
注意:在此类循环结构中,需要适当的添加continue或break控制语句,以使得无限循环可控;
例子:
guess number:
#!/bin/bash
#本脚本取100以内的整数,猜出取数的随机数;
#设定随机取值范围1-100,RANDOM内数字取模后范围在100以内,再加1,表示这次脚本随机取值范围在1-100;
NUMBER=$[RANDOM%100+1]
while true ; do
#与用户交互,让用户输入一个整数;
read -p "Input a number: " INPTNUM
#让用户输入的整数与随机取出的数比较,三种情况对应显示回应;
if [ $INPTNUM -gt $NUMBER ] ; then
echo "Too big"
elif [ $INPTNUM -lt $NUMBER ] ; then
echo "Too small"
else
echo "Yes! you WIN. That's $NUMBER."
#break命令打破死循环;
break
fi
done
#回收变量
unset NUMBER INPUTNUM
#!/bin/bash
#本脚本取100以内的整数,猜出取数的随机数;
#设定随机取值范围1-100,RANDOM内数字取模后范围在100以内,再加1,表示这次脚本随机取值范围在1-100;
NUMBER=$[RANDOM%100+1]
until false ; do
#与用户交互,让用户输入一个整数;
read -p "Input a number: " INPTNUM
#让用户输入的整数与随机取出的数比较,三种情况对应显示回应;
if [ $INPTNUM -gt $NUMBER ] ; then
echo "Too big"
elif [ $INPTNUM -lt $NUMBER ] ; then
echo "Too small"
else
echo "Yes! you WIN. That's $NUMBER."
#break命令打破死循环;
break
fi
done
#回收变量
unset NUMBER INPUTNUM
2.实现遍历功能的while和until循环结构:
while read LINES;do
COMMANDS
done < /PATH/FROM/SOMEFILE
until ! read LINES;do
COMMANDS
done < /PATH/FROM/SOMEFILE
注意:在做遍历循环时,建议使用for;
select循环结构:
select: select NAME [in 词语 ... ;] do 命令; done
从列表中选取词并且执行命令。(类似于for循环的遍历)
select循环也是一种遍历列表的方式创建一个可视化菜单,每个列表都有一个数字编号与之对应,供用户选择使用;而用户只需要选择其编号即可;
select是一种默认无限循环结构,因此,必须在循环体中为select提供退出循环的条件,通常可以使用break或exit命令实现;
通常情况下,select循环会和case一起使用,以进行合理的取值判断;
在脚本中实现的格式:
select VAR_NAME in LIST ; do
COMMANDS
done
写一个脚本,显示以/bin/bash为默认shell的用户的id信息:
#!/bin/bash
#本脚本显示以/bin/bash为默认shell的用户的id信息:
#awk命令获取/etc/passwd下以“:”分隔以/bin\/bash为结尾的用户的id;
select I in $(awk -F : '/\/bin\/bash$/{print $1}' /etc/passwd) quit ; do
#如果I的值为quit直接执行退出命令,否则就显示用户的id信息;
case $I in
quit)
exit
;;
*)
echo "The UID of $I is $(id -u $I)"
;;
esac
done
#回收变量;
unset I