今天学习了Linux Shell中的控制结构。其实大多数语言的控制结构这一块都是基本类似的,有了C语言的基础之后,对于shell中的控制结构是可以很快掌握的。
在C语言中无论是while,do…while,for这些控制语句里都含有条件测试语句。可以说在控制开始或者控制过程中条件测试都是必不可少的部分。
条件测试命令test用于评估表达式的值以便进行条件控制。test命令有两种书写格式。分别如下:
test 表达式
或者
[ 表达式 ]
test命令评估表达式参数,如果表达式的值为真,其退出状态为0(成功),否则退出状态为1(失败)。
注意:使用方括号时,“[”右边和“]”左边各需要至少一个空格。
比如:
biantiao@lazybone1994-ThinkPad-E430:~$ cd sh
biantiao@lazybone1994-ThinkPad-E430:~/sh$ test "3" \> "2" ; echo $?
0
biantiao@lazybone1994-ThinkPad-E430:~/sh$ test "2" \> "3" ; echo $?
1
biantiao@lazybone1994-ThinkPad-E430:~/sh$
test命令可以和多种系统运算符一起使用。这些运算符可以分成4类:文件属性测试运算符,字符串测试运算符,数值测试运算符和逻辑测试运算符。至于这些具体的测试运算符是没有必要去记忆的,在实际的编程中遇到了直接去查阅手册就好了。
test命令很强大,但只能执行算术比较运算且书写繁琐,为此,bash提供了专门执行整数算术运算的let命令,其语法格式为:
let 算术表达式..
或者
((算术表达式))
如果算术表达式求值为0,则设置退出状态为1;如果求值为0值,则退出状态为0。比如:
biantiao@lazybone1994-ThinkPad-E430:~$ let x=2 y=2**3 z=y*3 ; echo $? $x $y $z
0 2 8 24
biantiao@lazybone1994-ThinkPad-E430:~$let x=8%2 ; echo $? $x
1 0
let命令除了提供了基本的算术运算符外,它还提供了几个C语言中没有的运算符如下表所示:
注明:因为按位或的符号在Markdown中无法被转义,故用的中文来说明。感觉自己好low啊! o(╯□╰)o 如果谁有好的办法还请告知我,感激不尽!
运算符 | 功能 |
---|---|
! | 逻辑非 |
~ | 按位取反 |
& | 按位与 |
^ | 按位异或 |
就是一条竖线 | 按位或 |
技巧:
- 使用(())形式时,即使表达式中有shell的特殊字符,也不必用双引号将其括起来。比如:
biantiao@lazybone1994-ThinkPad-E430:~$ let "v = 6 | 5" ; echo $v
7
biantiao@lazybone1994-ThinkPad-E430:~$ let v = 6 | 5 ; echo $v
bash: let: =: 语法错误: 需要操作数 (错误符号是 "=")
5:未找到命令
7
biantiao@lazybone1994-ThinkPad-E430:~$ ((v = 6 | 5)) ; echo $v
7
biantiao@lazybone1994-ThinkPad-E430:~$
biantiao@lazybone1994-ThinkPad-E430:~$ v=$((1 + 2)) ; echo $? ; echo $v
0
3
biantiao@lazybone1994-ThinkPad-E430:~$
同“(( ))”一样,该命令可以对文件名和字符串使用更自然的语法,其中的特殊字符不用转义。在该命令中,还允许使用括号和逻辑操作符“&&”和“||”把test命令支持的测试组合起来。比如:
biantiao@lazybone1994-ThinkPad-E430:~$ [[ ( -d "$HOME" ) && ( -w "$HOME" ) ]] && echo "home is a writable dir ectory"
home is a writable dir ectory
biantiao@lazybone1994-ThinkPad-E430:~$
shell的控制语句所完成的功能与C语言中的控制语句相同,唯一的区别是它们的表达形式不一样。
if 测试条件1
then
命令组1
[elif 测试条件2]
[then
命令组2]
[else
命令x]
fi
说明:其中在方括号中的是可选的,按需选择。举个例子:
biantiao@lazybone1994-ThinkPad-E430:~/sh$ cat if.sh
#! /bin/bash
echo 'type in the user name.'
read user
if grep $user /etc/passwd > /tmp/null && who | grep $user
then
echo "$user has logged in the system"
cp /tmp/null ~/me.tmp
rm /tmp/null
else
echo "$user has not logged in the system"
fi
biantiao@lazybone1994-ThinkPad-E430:~/sh$ chmod a+x if.sh
biantiao@lazybone1994-ThinkPad-E430:~/sh$ ./if.sh
type in the user name.
biantiao
biantiao :0 2015-07-20 07:25 (:0)
biantiao pts/3 2015-07-20 13:34 (:0.0)
biantiao has logged in the system
biantiao@lazybone1994-ThinkPad-E430:~/sh$ ./if.sh
type in the user name.
lazybone1994
lazybone1994 has not logged in the system
biantiao@lazybone1994-ThinkPad-E430:~/sh$
case 字符串 in
模式字符串1) 命令
命令
命令
...
命令;;
模式字符串2) 命令
命令
命令
...
命令;;
...
模式字符串n) 命令
命令
命令
...
命令;;
esac
比如:
biantiao@lazybone1994-ThinkPad-E430:~$ cd sh
biantiao@lazybone1994-ThinkPad-E430:~/sh$ cat case.sh
#! /bin/bash
echo "Pleae input the file name."
read name
echo "Please chose either 1, 2 or 3."
echo "[1]ls -l $name"
echo "[2]cat $name"
echo "[3]quit"
read response
case $response in
1) ls -l $name;;
2) cat $name;;
3) echo "good bye."
esac
biantiao@lazybone1994-ThinkPad-E430:~/sh$ ./case.sh
Pleae input the file name.
case.sh
Please chose either 1, 2 or 3.
[1]ls -l case.sh
[2]cat case.sh
[3]quit
2
#! /bin/bash
echo "Pleae input the file name."
read name
echo "Please chose either 1, 2 or 3."
echo "[1]ls -l $name"
echo "[2]cat $name"
echo "[3]quit"
read response
case $response in
1) ls -l $name;;
2) cat $name;;
3) echo "good bye."
esac
biantiao@lazybone1994-ThinkPad-E430:~/sh$
说明:模式字符串可以使用通配符。如果一个模式字符串中包含了多个模式,那么各模式之间应该以竖线隔开(|)表示各模式是“或”的关系。比如:
biantiao@lazybone1994-ThinkPad-E430:~/sh$ cat m.sh
#! /bin/bash
read choice
case $choice in
time | date) echo "the time is `date`.";;
dir | path) echo "current directory is `pwd`.";;
*) echo "bad argument."
esac
biantiao@lazybone1994-ThinkPad-E430:~/sh$ ./m.sh
time
the time is 2015年 07月 20日 星期一 14:00:10 CST.
biantiao@lazybone1994-ThinkPad-E430:~/sh$ ./m.sh
date
the time is 2015年 07月 20日 星期一 14:00:17 CST.
biantiao@lazybone1994-ThinkPad-E430:~/sh$ ./m.sh
dir
current directory is /home/biantiao/sh.
biantiao@lazybone1994-ThinkPad-E430:~/sh$ ./m.sh
path
current directory is /home/biantiao/sh.
biantiao@lazybone1994-ThinkPad-E430:~/sh$ ./m.sh
kkh
bad argument.
biantiao@lazybone1994-ThinkPad-E430:~/sh$
while 测试条件
do
命令表
done
until 测试条件
do
命令表
done
说明:until语句与while语句很相似,只是测试条件不同。until语句中,只有当测试条件为假时才执行循环体中的命令表,直到测试条件为真时终止循环。
for 变量 [in 值表]
do
命令表
done
举个例子:
biantiao@lazybone1994-ThinkPad-E430:~/sh$ cat for.sh
#! /bin/bash
student=(张三 李四 王五 LazyBone1994)
for name in "${student[@]}"
do
echo $name
done
biantiao@lazybone1994-ThinkPad-E430:~/sh$ ./for.sh
张三
李四
王五
LazyBone1994
biantiao@lazybone1994-ThinkPad-E430:~/sh$
说明:该方式和C语言当中的for语句及其类似。
for ((e1; e2; e3)) ; do
命令表
done
举个例子:
biantiao@lazybone1994-ThinkPad-E430:~/sh$ cat for1.sh
#! /bin/bash
echo "输入要打印的行数:"
read n
for ((i = 1; i <= n; i++)) ; do
for ((j = 1; j <= i; j++)) ; do
echo -n "* "
done
echo ""
done
biantiao@lazybone1994-ThinkPad-E430:~/sh$ ./for1.sh
输入要打印的行数:
6
*
* *
* * *
* * * *
* * * * *
* * * * * *
biantiao@lazybone1994-ThinkPad-E430:~/sh$
break [n]
说明:其中n为一整数,表示要跳出几层循环。
continue [n]
说明:其中n表示包含continue语句的最外层循环体向外跳出基层循环,默认值为1.
exit [n]
说明:n是设定的退出状态。如果未显示给出n值,则退出状态为最后一个命令的执行状态。