- 选择执行:if语句
- 条件判断:case语句
- 循环控制:for语句
- 循环控制:while语句和until语句
- 循环控制:continue, break, shift语句
- 循环控制:select语句
- 信号捕捉:trap语句
一、选择执行:if 语句
- 单分支
if 判断条件; then
判断条件为真的代码
fi
- 双分支
if 判断条件; then
判断条件为真的代码
else
判断条件为假的代码
fi
- 多分支:逐条件判断,直到满足条件执行分支代码,忽略之后的条件判断
if 判断条件1; then
判断条件1为真的代码
elif 判断条件2; then
判断条件2为真的代码
elif 判断条件3; then
判断条件3为真的代码
...
else
上述所有条件为假的代码
fi
- 实验:当运行脚本时已经自带参数,输出参数值;若运行脚本时没有自带参数,则提示输入参数,并输出参数值
#! /bin/bash
if [ $# -eq 0 ] ;then
read -p "please type the words: " words
else
words=$*
fi
echo $words
二、条件判断:case 语句
- 语法:
case 变量引用 in
PAT1)
分支语句1
;;
PAT2)
分支语句2
;;
PAT3)
分支语句3
;;
...
*)
默认分支语句
;;
esac
PAT:支持glob通配符
*:任意长度任意字符
?:任意单个字符
[]:指定范围内的任意单个字符
a|b:a或b实现一个菜单:
序号 | 菜名 | 价格 |
---|---|---|
1 | lamian | 10 |
2 | huimian | 10 |
3 | yangroutang | 20 |
4 | gaifan | 15 |
5 | jiaozi | 20 |
要求输入菜名序号后,显示出相应菜品的价格
#! /bin/bash
cat <<eof
menu:
1) lamian
2) huimian
3) yangroutang
4) gaifan
5) jiaozi
eof
read -p "choose your menu(eg:1): " menu
case $menu in
1|2)
echo "menu $menu price is 10"
;;
3|5)
echo "menu $menu price is 20"
;;
4)
echo "menu $menu price is 15"
;;
*)
echo "wrong menu"
;;
esac
三、循环控制:for 语句
- 循环结构的基本组成:初始值、循环开始和结束条件、循环体
(1)基本用法:
- 语法:
for 变量名 in 列表; do
循环体
done
执行机制:
依次将列表中的元素赋值给“变量名”; 每次赋值后即执行一次循环体; 直到列表中的元素耗尽,循环结束-
列表生成方式:
- 直接给出列表
- 整数列表: {start..end}, {start..end...step}
- 返回列表的命令:$(COMMAND) 或 `COMMAND`,如 $(seq start step end)
- 使用glob:*.sh
- 变量引用:$@, $*
(2)特殊用法(双小括号方法):
双小括号法:用两组括号嵌套
(())
,可以实现C语言风格变量操作,如
let i++
等同于((i++))
-
for 循环的特殊格式
- 语法:
for ((控制变量初始化;条件判断表达式;控制变量的修正表达式)); do
循环体
done
控制变量初始化:仅当运行到循环代码段开始时执行一次
控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算,而后再做条件判断
实验:建立一个10*10矩阵,每个位置以“行号.列号”方式命名,如第1行第3列的内容为1.3
#! /bin/bash
for i in {1..10}; do
for j in {1..10}; do
echo -ne "$i.$j\t"
done
echo
done
***另一种实现***
#! /bin/bash
for ((i=1;i<=10;i++));do
for ((j=1;j<=10;j++));do
echo -ne "$i.$j\t"
done
echo
done
四、循环控制:while 语句和until 语句
(1)while 语句
- 语法:
while CONDITON ; do
循环体
done
CONDITION 循环控制条件
值为true或false,只有为true时才能执行循环体,一般在循环体中有循环控制变量在每一次循环中变化,最终使CONDITION值由true转变为false,从而终止循环进入条件:CONDITION=true
退出条件:CONDITION=false无限循环:
while true; do
COMMANDs
done
- 特殊用法:遍历文件的每一行
while read line ; do
循环体
done < /path/to/file //依次读取/path/to/file文件的每一行,并将行复制给变量line
- 实验:判断/etc/passwd文件每个用户是系统用户还是普通用户(CentOS 7)
#! /bin/bash
while read userline; do
userid=`echo $userline | cut -d: -f3`
username=`echo $userline | cut -d: -f1`
if (( userid < 1000 )); then
echo "$username is system user"
else
echo "$username is common user"
fi
done < /etc/passwd
(2)until 语句
- 语法:
until CONDITION ; do
循环体
done
CONDITION循环控制条件
值为false时执行循环体,当值为true时,终止循环进入条件:CONDITION=false
退出条件:CONDITION=true无限循环:
until false; do
COMMANDs
done
五、循环控制:continue, break, shift语句
(1)continue 语句
continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断
最内层为第1层不写层数默认为第1层
在循环体中使用,语法:
while CONDITION1; do
CMD1
...
if CONDITION2; then
continue //continue命令表示跳出本轮循环,直接下一轮循环开始判断CONDITION1值
fi
CMDn
...
done
- 实验:输出与上文类似的10*10矩阵,但是行号与列号相同的位置为空白
#! /bin/bash
for i in {1..10}; do
for j in {1..10}; do
[ $j -eq $i ] && { echo -ne "\t";continue; } //行号与列号相同时,输出制表符,跳出本轮循环
echo -ne "$i.$j\t"
done
echo
done
(2)break 语句
break [N]:提前结束第N层循环
最内层为第1层不写层数默认为第1层
在循环体中使用,语法:
while CONDITION1; do
CMD1
...
if CONDITION2; then
break //continue命令表示跳出本层循环,执行本层循环外的语句
fi
CMDn
...
done
- 实验:输出与上文类似的10*10矩阵,但是列号大于等于行号的位置为空白
#! /bin/bash
for i in {1..10}; do
for j in {1..10}; do
[ $j -eq $i ] && break //行号与列号相同时,终止本层循环,故列号大于行号的位置也没有机会输出
echo -ne "$i.$j\t"
done
echo
done
(3)shift 语句
语法:
shift [N]
用于将参数列表左移N次,缺省为左移一次
参数列表一旦被移动,最左端的那个参数就从列表中删除
while 循环遍历位置参量列表时,常用到shift
实验:
(1)输入n个参数,第1行输出第1-n个参数,第2行输出第2-n个参数,以此类推,直到第n行输出第n个参数
#! /bin/bash
while [ $# -gt 0 ]; do
echo "$*"
shift
done
(2)输入n个参数,每行输出一个参数
#! /bin/bash
until [ -z "$1" ];do
echo "$1"
shift
done
六、循环控制:select 语句
- 语法:
select variable in list; do
循环体命令
done
select 循环主要用于创建菜单,按数字顺序排列的菜单项将显示在标准错误上,并显示PS3 提示符,等待用户输入
用户输入菜单列表中的某个数字,执行相应的命令
用户输入被保存在内置变量REPLY 中
select是个无限循环,因此要记住用break命令退出循环,或用exit命令终止脚本,也可以按ctrl+c退出循环
select经常和case联合使用
实验:实现一个菜单,输入菜单编号显示价格,不存在的菜单号显示"wrong menu"并退出
序号 | 菜名 | 价格 |
---|---|---|
1 | lamian | 10 |
2 | huimian | 10 |
3 | yangroutang | 20 |
4 | gaifan | 15 |
5 | jiaozi | 20 |
#! /bin/bash
PS3="please type the menu num: " //环境变量PS3指定提示符格式
select menu in lamian huimian rangroutang gaifan jiaozi; do
case $REPLY in //用户的输入自动存入REPLY变量中
1)
echo "the price of lamian is \$10"
;;
2)
echo "the price of huimian is \$10"
;;
3)
echo "the price of rangroutang is \$20"
;;
4)
echo "the price of gaifan is \$15"
;;
5)
echo "the price of jiaozi is \$20"
;;
*)
echo "wrong menu"
break //select语句默认无限循环,需要有break命令退出循环
;;
esac
done
七、信号捕捉:trap 语句
trap '触发指令' 信号
进程收到系统发出的信号后,执行触发指令,而不执行信号操作trap ' ' 信号
进程收到系统发出的信号后,直接忽略trap '-' 信号
进程收到系统发出的信号后,恢复信号操作
*trap -p
列出自定义信号操作
- 实验:trap语句验证,以信号2 SIGINT为例
#! /bin/bash
trap 'echo "signal:sigint"' sigint //接到sigint信号输出"signal:sigint"
trap -p
for (( i=1;i<=5;i++ )); do
echo $i
sleep 2
done
trap ' ' sigint //接到sigint信号直接忽略
trap -p
for (( j=6;j<=10;j++ )); do
echo $j
sleep 2
done
trap '-' sigint //接到sigint信号恢复信号操作
trap -p
for (( k=11;k<=15;k++ )); do
echo $k
sleep 2
done
共3个循环,每个循环开始前都输出了相应的自定义信号情况
输出1-5时,Ctrl+C发出sigint信号后,直接执行替换的命令echo "signal:sigint
,循环继续
输出6-10时,Ctrl+C发出sigint信号后,直接忽略信号,循环继续
输出11-15时,Ctrl+C发出sigint信号后,恢复信号本身作用,循环被终止