0%

Linux-10-shell流程控制:条件、循环与函数

expr后面第一个字符串要双引号

条件

shell中的逻辑判断

条件判断的依据

判定一条命令是否执行成功。方法:命令执行的返回码,0表示成功,非0表示失败。可以把命令执行结束后的“返回码”理解为“出错代码”

命令执行结束后的返回码

如果代码中main()函数没有return一个确定的值,返回码就是随机值,不可用来做条件判断

内部变量$?

echo $? $?上一命令的返回码,shell自定义变量

复合逻辑

可以用这种方式代替if else

用&&或||连结两个命令,可以利用复合逻辑中的“短路计算”特性实现最简单的条件

  • cmd1 && cmd2
    若cmd1执行成功(返回码为0)则执行cmd2,否则不执行cmd2
  • cmd1 || cmd2
    cmd1执行失败(返回码不为0)则执行cmd2,否则不执行cmd2

test及方括号命令

命令test与[\

  • 命令/usr/bin/[要求其最后一个命令行参数必须为]
  • 除此之外/usr/bin/[与/usr/bin/test功能相同
    • 有的Linux系统中/usr/bin/[是一个指向test的符号连接
  • 注意:不要将方括号理解成一个词法符号
  • 举例
1
2
test -r /etc/motd
[ -r /etc/motd ]

文件特性检测

  • -f 普通文件
  • -d 目录文件
  • -r 可读
  • -w 可写
  • -x 可执行
  • -s size>0
1
2
test -r /etc/motd && echo readable
[ -r /etc/motd ] && echo readable

字符串比较

str1 = str2 str1与str2串相等
str1 != str2 str1串与str2串不等
注意:等号和不等号两侧的空格不可少
[ "$a" = "" ] && echo empty string 注意:$a的引号

整数比较

整数的比较(六种关系运算,注意与字符串比较的区别)

命令 符号
-eq
-ne
-gt
-ge
-lt
-le

例:

1
test `ls | wc -l` -ge 100 && echo "Too many files"

复合条件

  • 逻辑运算
    • ! NOT(非)
    • -o OR (或)
    • -a AND (与)
      例:
1
[ ! -d $cmd -a -x $cmd ] && $cmd

注意:必需的空格不可省略

命令组合

命令组合的两种方式{}与()

  • 命令组合类似C语言中的复合语句,组合在一起的几个命令作为一个整体看待:
    可以集体管道和重定向或者当条件满足时执行若干个命令。
1
2
3
4
5
6
7
8
pwd
DIR=/usr/bin
[ -d $DIR ] && {
cd $DIR
echo "Current Directory is `pwd`"
echo "`ls | wc -l` files"
}
pwd
{}与()在语义上的不同
  • {} 在当前shell中执行一组命令
  • () 在子shell中执行一组命令
{}与()在语法上的不同
1
2
3
4
5
(list) #在子shell中执行命令表list
{ list;} #在当前shell中执行命令表list

#注意:左花括号后面必须有一个空格
#圆括号是shell元字符,花括号不是,它作为一个特殊内部命令处理。所以必须是一行的行首单词

条件结构if

语法

1
2
3
4
5
6
7
8
9
if condition
then list
elif condition
then list
else
list
fi

#其中:if/then/elif/else/fi为关键字(内部命令)

注意

  • then行可和cat行合并成一行
  • if行不可以和then行直接合并成一行
  • 将两行合并: 分号使得一行内可以输入多条命令
    if test -r errfile; then
  • 与C语言不同,if的语法中then与else或fi配对,使得不需要花括号这样的命令组合

case结构:多条件分支

语法

1
2
3
4
5
case word in
pattern1) list1;;
pattern2) list2;;
...
esac

注意

  • word与pattern匹配:使用shell的文件名匹配规则
  • ;;是一个整体,不能在两分号间加空格,也不能用两个连续的空行代替
  • 可以使用竖线表示多个模式
  • word与多个模式匹配时,执行遇到的第一个命令

注释

shell中使用#号作注释

循环

表达式运算

  • shell不支持除字符串以外的数据类型,不支持加减乘除等算数运算和关于字符串的正则表达式运算
  • 需要这些功能,借助于shell之外的可执行程序/usr/bin/expr实现
  • 有的shell(包括bash)为了提高执行效率,提供内部命令版本的echo,printf,expr,test,[等命令,但这仅仅是一种性能优化措施。只依赖外部命令完全可以实现
  • bash提供的这种机制使得程序员可以根据需要自己设计更多更方便的运算

expr命令:算术运算、关系运算、逻辑运算、正则表达式运算

  • 括号
    ()
  • 算数运算(5种)
    + - * / %
  • 关系运算(6种)
    > >= < <= = !=
  • 逻辑运算(2种)
    | &
  • 正则表达式运算
1
2
3
4
5
#例 a=2;b=8;c=10;求x=a*(b+c),y=a+4<b并且c不等于8
x=`expr $a \* \( $b + $c \)`
y=`expr \( $a + 4 \< $b \) \& \( $c != 8 \)`
x=`expr $a '*' '(' $b + $c ')'`
y=`expr '(' $a + 4 '<' $b ')' '&' '(' $c != 8 ')'`

注意

  • 算术运算、关系运算和逻辑运算,shell脚本用到的时候不是很多
  • 应该转义的地方必须加反斜线转义
  • 应该有空格的地方不允许漏掉

while循环

while结构

1
2
3
while condition
do list
done

内部命令eval

将程序中输入的或者加工出来的数据作为程序来执行

for结构

语法一

1
2
3
for name in word1 word2 ...
do list
done

语法二

1
2
3
4
5
6
7
for name
do list
done
#相当于
for name in $1 $2 ...
do list
done

break,continue,exit

  • 内部命令break
    循环结构for/while中使用,中止循环
    例:
1
2
break
break 2
  • 内部命令continue
    在循环结构for/while中使用,提前结束本轮循环
  • 内部命令exit
    结束脚本程序的执行,退出。exit的参数为该进程执行结束后的返回码
    例:exit 1

函数

shell函数

  • 语法
    name() { list;}
  • 参数引用
    • 函数定义完成之后,该函数名作为一个自定义内部命令执行,后面可以调用
    • 调用时函数名后附加上0到多个参数
    • 在函数体内部以$1,$2,…或$*,$@方式引用
  • 返回值
    • 函数体内用内部命令return使函数有返回码,0表示成功,非零表示失败
    • 函数内部可以创建和修改变量,函数返回后其它程序可以访问