首页 > 代码库 > 《学习bash》笔记--流程控制

《学习bash》笔记--流程控制

bash支持下述流程控制结构:

if/else:如果某条件为真/假,执行一个执行列表。

for:执行一个语句列表固定次数。

while:当某条件为真时重复执行某语句列表

until:重复执行某语句列表直至某条件为真。

case:依据一个变量取值执行几个语句列表中的一个。

select:允许用户从一个菜单的可选列表中选择一个。


1.if/else

最简单的流程控制结构类型时嵌入在bash的if语句中的条件语句。当选择做或者不做某件事情或者依据条件表达式的真或者假

从数量不多的几个事情里选择一个进行操作时可以使用条件语句。条件语句测试包含shell变量的值,文字字符特征,命令是否

成功及其他因素。

if结构语法如下:

if condition

then

  statements

[elif condition

  then statements]

[else

  statements]

fi


1.1退出状态和返回

if检查if关键字后的列表中最后一个语句的退出状态。该列表通常指示一个语句,如果状态为0,则条件评估为真,如果是其他,
条件为假。该情况对elif语句下的每个条件也适用。
例如a.sh的内容如下:
if cd $1;
then
echo "OK"
else
echo "NG"
fi
执行结果:
#./a.sh 1
./a.sh: line 1: cd: 1: No such file or directory
NG
# ./a.sh /dev
OK
对于脚本中分号,是用来隔断每个语法关键字或命令的。上面的格式分号写与不写效果一样,但是如果写成如下:
if cd $1;then echo "OK";else echo "NG";fi
不写分号就会出错。

需要的第二个特性时语句return N,它使得包含它的函数以状态N退出。N实际上可选,其默认为最后一个命令的退出状态,没有
以return语句结束的函数将返回最后一个语句返回的状态。return只能用在函数以及使用source执行的shell脚本内,相比较,语句
exit N将退出整个脚本,而不管其嵌套在函数内多少层。

1.2.组合退出状态

bash允许你逻辑上组合退出状态,这样就可以一次测试多个内容。
语法 statement1 && statement2意思时执行statement1,如果其退出状态为0,则执行statement2。
语法statement1 || statement2刚好相反:执行statement1,如果其退出状态非0,则执行statement2。

1.3.条件测试

shell使用[......]结构提供了测试各种条件的方式。可以使用该结构检验一个文件的各种属性,或比较两个文件哪个更新,以及对字符
串进行比较。
[#condition#]返回一个退出状态,给出condition是否为真的信息。[]中的空格是必须的。

1.3.1.字符串比较

str1 = str2
则str1匹配str2
str1 != str2
str1不匹配str2
str1 \< str2
str1小于str2
str1 \> str2
str1大于str2
-n str1
str1为非null,即长度大于0. 也可以直接使用[ “$str1” ]。
-z str1
str1为null,即长度为0.

其中注意的是,使用<,>时需要转义,而且比较符两边的空格不能少,不然会被认为是一个字符串。
例如a.sh内容如下:
str1="132"
str2="125"
if [ $str1 \> $str2 ]
then
echo "str1 is bigger than str2"
else
echo "str1 is not bigger than str2"
fi
执行结果:
str1 is bigger than str2.
脚本依次比较字符串中的字符的ascii码来判断大小。

1.3.2.文件属性检查

-d file
file存在并且为一个目录。
-e file
file存在。
-f file
file存在并且为一常规文件(亦即不是一个目录或其他特殊类型文件)
-r file
对文件有读权限
-s file
文件存在并且非空
-w file
对file有写权限
-x file
对file有可执行权限,如果为目录,则有目录搜索权限
-O file
你是file的所有者
-G file file组ID匹配你的ID(如果你在多个组中,则匹配其中一个)
file1 -nt file2
file1比file2新
file1 -ot file2
file1比file2旧

也可以在条件表达式前加上!符号否定其真值,这样只有表达式为假时,!expr值才为真。另外,可以通过使用圆括号用斜线转义
防止shell对其进行特殊处理将值分组或使用没有介绍过的两个逻辑操作符:-a(AND)和-o(OR),进而实现条件操作符的复杂
逻辑表达式。
例如:
if[ \(-n $dirname1\) -a \(-n $dirname2\)  ] then
只有dirname1和dirname2都不为空时才执行。

1.3.3.整数条件

shell还提供算数测试集合。他们比较字符串的数字值。
-lt 小于
-le 小于等于
-eq 等于
-ge 大于等于
-gt 大于
-ne 不等于

2.for

for循环允许你重复一段代码固定次数,在循环代码执行期间,一个称为循环变量的特殊变量被赋予了不同的值;这样每个
循环的功能就有了细微的差别。
for循环很适合处理命令行上的参数以及文件集,for结构的语法如下:
for name [in list]
do
statements
done
list为名称列表,如果in list被省略,列表默认为"$@",即命令行参数的引用列表。
例如a.sh的内容如下:
for folder in "$@"
do
        echo -e "\t$folder"
done
执行结果如下:
$ ./a.sh a b c
       a
       b
       c
其中echo的-e选项使tab识别被转义的格式化字符,这里为/t.顺便提下-n选项,该选项令echo在结尾不打印LINEFEED。

3.case

case的结构使你依据可包含通配符的模式测试字符串,时你以一种更精确的方式表示一系列if-then-else类型的语句。
case的语法如下:
case expression in
  pattern1)
    statements;;
  pattern2)
    statements;;
esac
任何pattern实际上都可以由管道字符|分隔的几个模式组成,如果expression匹配其中一个模式。其相应语句被执行。如果存在
几个管道字符分隔的模式,表达式会尝试匹配其中的每一个以使相应语句被执行。模式被按次序检测,直至成功匹配。如果每一个
都匹配不上,则不执行任何动作。
需要注意的是,statements以两个分号结尾。
例如a.sh的内容如下:
for filename in "$@"
do
case $filename in
*.doc|*.docx)
echo "$filename:doc file";;
*.txt)
echo "$filename:txt file";;
*)
echo "$filename:unknown file";;
esac
done
执行结果:
$ ./a.sh a.txt b.doc c.docx d.pdf
a.txt:txt file
b.doc:doc file
c.docx:doc file
d.pdf:unknown file

4.select

select使你可以很容易地生成菜单。其语法:
select name [in list]
do
statements
done
像for一样,你可以省略in list,被默认为“$@”,即引用的命令行参数列表,select功能如下:
1.生成列表内每一条目的逃单,并且将之格式化,使其每一个选择对应一个数字。
2.提示用户输入数字。
3.将已选择条目保存在变量name内,已选择编号保存在内置变量REPLY中。
4.执行条目内的语句。
5.无限循环该过程。
break时退出select循环的chang
例如a.sh的内容如下:
PS3="directory?"
select folder in "$@" 
do
echo "the num is $REPLY,$folder is selected"
break
done
执行结果:
$ ./a.sh a b c d
1) a
2) b
3) c
4) d
directory?1
the num is 1,a is selected

5.while和until

while的语法如下:
while 条件测试
do
执行命令
done

首先进行条件测试,如果传回值为0(条件测试为真),则进入循环,执行命令区域,否则不进入循环。

例如a.sh内容如下:

i=1
while [ $i -le 5 ];
do
        echo "$i"
        ((i=i+1))
done

执行结果如下:

# ./a.sh
1
2
3
4
5


until的语法如下:

until 条件测试
do
执行命令
done

如果条件测试结果为假(传回值不为0),就进入循环。

例如a.sh内容如下:

i=1
until [ $i -gt 5 ];
do
        echo "$i"
        ((i=i+1))
done

执行结果如下:

# ./a.sh
1
2
3
4
5