shell控制流结构
控制结构
if then else语句
case语句
until循环
while循环
break控制
confinue控制
一、 流控制的目的
#!/bin/bash
#创建一个目录
make /home/jianliu/shelltest/txt
#复制所有txt文件到指定目录
cp *.txt /home/jianliu/shelltest/txt
rm -f *.txt
1.该脚本运行存在问题:很可能创建目录失败,后续操作无法执行。
2. 若目录创建失败,该如何处理;成功又该如何处理;
3. 文件拷贝失败如何处理
—-》因此引用流控制结构来控制脚本的有效运行。
1. 条件测试(判断)—test
有时判断字符串是否相等或检查文件状态或是数字测试等。Test命令用于测试字符串,文件状态和数字。
Test 判断的结果如何正确的判断?不要直接用直觉,注意test后面的表达式是一个整体,注意这个整体的结果是成功还是失败,成功返回0,失败返回1
【1】 文件状态测试
===== 格式(两种写法)
格式 | 注意事项 |
---|---|
test condition | |
[ condition ] | 使用方括号时,要注意在条件两边加上空格!!! |
格式(两种写法)
test condition
[ condition ] #使用方括号时,要注意在条件两边加上空格。
eg: [ -x file ] (正确) [-x file](错误!!)
文件测试状态 :测试的结果可以用$?的值来判断,0表示成功,其他为失败
-d 目录 -s 文件长度大于0、非空
-f 正规文件 -w 可写
-L 符号链接 -u 文件有suid位设置
-r 可读 -x 可执行
-z 字符串为空 -e 文件是否存在
—–实例:
jianliu@ubuntu:~/aa$ ls -a
. .. 2.c a1.c app2 b1.c b3.c b4.c bb hello.c shell02.sh
jianliu@ubuntu:~/aa$ ls -a -ls
total 36
4 drwxrwxr-x 3 jianliu jianliu 4096 Oct 7 20:07 .
4 drwxr-xr-x 24 jianliu jianliu 4096 Oct 7 19:51 ..
0 lrwxrwxrwx 1 jianliu jianliu 3 Oct 7 20:07 2.c -> 1.c
4 -rw-rw-r-- 1 jianliu jianliu 79 Oct 3 05:05 a1.c
12 -rwxrwxr-x 1 jianliu jianliu 8501 Oct 6 19:26 app2
0 lrwxrwxrwx 1 jianliu jianliu 4 Oct 7 20:07 b3.c -> b1.c
0 lrwxrwxrwx 1 jianliu jianliu 4 Oct 7 20:07 b4.c -> b1.c
4 drwxrwxr-x 3 jianliu jianliu 4096 Oct 3 06:44 bb
4 -rw-rw-r-- 1 jianliu jianliu 94 Oct 4 04:20 hello.c
4 -rwxr-xr-x 1 jianliu jianliu 109 Oct 6 19:15 shell02.sh
jianliu@ubuntu:~/aa$ test -d bb
jianliu@ubuntu:~/aa$ echo $?
0 #bb为目录文件
jianliu@ubuntu:~/aa$ test -L 2.c
jianliu@ubuntu:~/aa$ echo $?
0 #2.c为link文件
jianliu@ubuntu:~/aa$ test -x shell02.sh
jianliu@ubuntu:~/aa$ echo $?
0 #shell02.sh为可执行文件
jianliu@ubuntu:~/aa$ [ -x shell02.sh ]
jianliu@ubuntu:~/aa$ echo $?
0
#脚本文件 test.sh 测试文件($1所指向的文件)是否可写。
#!/bin/bash
echo "test use 1"
test -w $1
if [ $? -eq "0" ]; then
echo "success ";
else
echo "error: not success";
fi
echo "return value:" $?
echo "test use 2 : using [] -- begin"
[ -w $1 ]
echo "return value:" $?
#测试---------------------------------------------
#新建一个自读文件 :rd_file
-r--r--r-- 1 jianliu jianliu 0 Oct 7 20:25 rd_file
#新建一个可写文件:hello.c
4 -rw-rw-r-- 1 jianliu jianliu 94 Oct 4 04:20 hello.c
jianliu@ubuntu:~/aa$ ./test.sh rd_file
test use 1
error: not success
return value: 0
test use 2 : using [] -- begin
return value: 1
jianliu@ubuntu:~/aa$ ./test.sh hello.c
test use 1
success
return value: 0
test use 2 : using [] -- begin
return value: 0
—–测试时使用逻辑操作符
操作符 | 作用 | 说明 |
---|---|---|
-a | 逻辑与(and) | 操作符两边均为真,结果为真,否则为假。 |
-o | 逻辑或(or) | 操作符两边一边为真,结果为真,否则为假。 |
! | 逻辑否 | 条件为假,结果为真。 |
#测试实例:
#逻辑与操作: 测试文件a1.c 与b1.c是否均可读
jianliu@ubuntu:~/aa$ [ -w b1.c -a -w a1.c ]
jianliu@ubuntu:~/aa$ echo $?
0
#逻辑或操作 : 测试test.sh 是否可执行 或者 a1.c是否可写
jianliu@ubuntu:~/aa$ [ -x test.sh -o -w a1.c ]
jianliu@ubuntu:~/aa$ echo $?
0
【2】 字符状态测试
测试两个字符是否相等。退出状态变量 $?,0表示成功,1表示失败。
#格式-----------------------:
(1) test string
(2) test [operator] string
(3) test string_1 [operator] string_2
(4) [ [operator] string ]
(5) [ string_1 [operator] string_2 ]
—- 操作数 operator 说明
操作数 | 作用说明 |
---|---|
= | 两个字符串相等 |
!= | 两个字符串不等 |
-z | 空串 |
-n | 非空串 |
*注意!!! =,!=都是针对字符串操作,而不是数值*
—–测试实例
jianliu@ubuntu:~/aa$ test "string"
jianliu@ubuntu:~/aa$ echo $?
0
jianliu@ubuntu:~/aa$ test -n "string"
jianliu@ubuntu:~/aa$ echo $?
0
jianliu@ubuntu:~/aa$ test "string1" = "string2"
jianliu@ubuntu:~/aa$ echo $?
1
jianliu@ubuntu:~/aa$ [ -n "string" ]
jianliu@ubuntu:~/aa$ echo $?
0
jianliu@ubuntu:~/aa$ [ "string1" = "string2" ]
jianliu@ubuntu:~/aa$ echo $?
1
jianliu@ubuntu:~/aa$ declare AAA="aaa"
jianliu@ubuntu:~/aa$ declare BBB="bbb"
jianliu@ubuntu:~/aa$ [ $AAA = $BBB ]
jianliu@ubuntu:~/aa$ echo $?
1
jianliu@ubuntu:~/aa$ [ 1 = 1 ] #看做字符
jianliu@ubuntu:~/aa$ echo $?
0
- 【3】 数值测试
----格式---------------------
(1) number1 [operator] number2
(2) [ number1 [operator] number2 ]
—- 操作数 operator 说明
操作数 | 作用说明 |
---|---|
-eq | 数值相等 |
-ne | 数值不相等 |
-gt | 第一个数大于第二个数。 |
-lt | 第一个数小于第二个数。 |
-le | 第一个数小于等于第二个数。 |
-ge | 第一个数大于等于第二个数。 |
—–实例—————-
jianliu@ubuntu:~/aa$ NUM1=12
jianliu@ubuntu:~/aa$ NUM2=34
jianliu@ubuntu:~/aa$ test $NUM1 -ne $NUM2
jianliu@ubuntu:~/aa$ echo $?
0
jianliu@ubuntu:~/aa$ [ $NUM1 -gt $NUM2 ]
jianliu@ubuntu:~/aa$ echo $?
1
jianliu@ubuntu:~/aa$ NUM3=130
jianliu@ubuntu:~/aa$ [ "$NUM3" -eq "130" ]
jianliu@ubuntu:~/aa$ echo $?
0
【4】expr数值运算
格式: expr argument1 [operator] argument2
——-注意!——-
(1) [operator] 前后都要有空格!!
(2) 这个表达式是命令!!!!
#eg------------------------:
VAR3=`expr $VAR1 \* $VAR2` #正确!!
VAR3=expr $VAR1 \* $VAR2 #错误!!
——-(3) 乘法操作: [operator] = \*
==========实例test===================
#加法操作
jianliu@ubuntu:~/aa$ expr 10 + 10
20
#减法操作
jianliu@ubuntu:~/aa$ expr 15 - 10
5
#除法操作
jianliu@ubuntu:~/aa$ expr 30 / 3
10
jianliu@ubuntu:~/aa$ expr 30 /2 #错误!!!
expr: syntax error
jianliu@ubuntu:~/aa$ expr 30/3
30/3
jianliu@ubuntu:~/aa$ expr 30 / 3 / 2
5
#乘法操作
jianliu@ubuntu:~/aa$ expr 30 \* 3 #\* 转义字符
90
jianliu@ubuntu:~/aa$ expr 30 * 3 #错误
expr: syntax error
#----------------------------------------------------
jianliu@ubuntu:~/aa$ MY_VAR1=21
jianliu@ubuntu:~/aa$ MY_VAR2=34
jianliu@ubuntu:~/aa$ MY_VAR3=`expr $MY_VAR1 + $MY_VAR2` #反引号!!,命令!!
jianliu@ubuntu:~/aa$ MY_VAR4=`expr $MY_VAR1 \* $MY_VAR2`
jianliu@ubuntu:~/aa$ echo $MY_VAR3
55
jianliu@ubuntu:~/aa$ echo $MY_VAR4
714
- 【5】 理论提高(man test)
man test
TEST(1) User Commands TEST(1)
-n STRING
the length of STRING is nonzero
STRING equivalent to -n STRING
-z STRING
the length of STRING is zero
STRING1 = STRING2
the strings are equal
STRING1 != STRING2
the strings are not equal
INTEGER1 -eq INTEGER2
INTEGER1 is equal to INTEGER2
INTEGER1 -ge INTEGER2
INTEGER1 is greater than or equal to INTEGER2
INTEGER1 -gt INTEGER2
INTEGER1 is greater than INTEGER2
INTEGER1 -le INTEGER2
INTEGER1 is less than or equal to INTEGER2
INTEGER1 -lt INTEGER2
INTEGER1 is less than INTEGER2
INTEGER1 -ne INTEGER2
INTEGER1 is not equal to INTEGER2
FILE1 -ef FILE2
FILE1 and FILE2 have the same device and inode numbers
FILE1 -nt FILE2
FILE1 is newer (modification date) than FILE2
FILE1 -ot FILE2
FILE1 is older than FILE2
-b FILE
FILE exists and is block special
-c FILE
FILE exists and is character special
-d FILE
FILE exists and is a directory
-e FILE
FILE exists
-f FILE
FILE exists and is a regular file
-g FILE
FILE exists and is set-group-ID
-G FILE
FILE exists and is owned by the effective group ID
-h FILE
FILE exists and is a symbolic link (same as -L)
-k FILE
FILE exists and has its sticky bit set
-L FILE
FILE exists and is a symbolic link (same as -h)
-O FILE
FILE exists and is owned by the effective user ID
-p FILE
FILE exists and is a named pipe
-r FILE
FILE exists and read permission is granted
-s FILE
FILE exists and has a size greater than zero
-S FILE
FILE exists and is a socket
-t FD file descriptor FD is opened on a terminal
-u FILE
FILE exists and its set-user-ID bit is set
-w FILE
FILE exists and write permission is granted
-x FILE
FILE exists and execute (or search) permission is granted
2. if then else fi 语句
- 语法1
if [ 条件 ]
then 命令
fi #终止符号
#注意if语句必须以fi终止
#---练习:----------------
#if test
if [ "13" -lt "12" ] # "13" 前一个空格,“13”后也有一个空格。
then
echo "yes 13 is less then 12"
else
echo "NO"
fi
- 语法2
if [ 条件1 ]
then
命令1
elif [ 条件2 ]
then
命令2
else
命令3
fi
- 综合练习——-
#脚本文件 判断输入字符是否空空串
#!/bin/bash
#if then fi
VAR=$1
if [ -z $VAR ]
then
echo "success1"
else
echo "failure1"
fi
if test -z $VAR #不建议使用这种格式!!!
then
echo "success2"
else
echo "failure2"
fi
#运行结果
jianliu@ubuntu:~/aa$ ./test.sh
success1
success2
jianliu@ubuntu:~/aa$ ./test.sh ""
success1
success2
jianliu@ubuntu:~/aa$ ./test.sh "haha"
failure1
failure2
#脚本 判断一个文件是否存在
#!/bin/bash
#if test
#this is a comment line
echo "Enter your filename:"
read myfile
if [ -e $myfile ] #判断文件是否存在
then
if [ -s $myfile ] #判断文件内容长度是否>=0
then
echo "$myfile exist and size greater than zero"
else
echo "$myfile exist but size is zero"
fi
else
echo "file no exist"
fi
#运行结果:-----------------------------------
jianliu@ubuntu:~/aa$ ./test.sh
Enter your filename:
c1.c
file no exist
jianliu@ubuntu:~/aa$ touch efile #新建一个空文件
jianliu@ubuntu:~/aa$ ./test.sh
Enter your filename:
efile
efile exist but size is zero
jianliu@ubuntu:~/aa$ ./test.sh
Enter your filename:
b1.c
b1.c exist and size greater than zero
3. case 多选择语句
—-类似于C语言中switch语句,但是在脚本中case处理的是字符串!!!
case多选择语句格式:
case 值(变量$VAR) in
模式1 )
命令1
;; #用两个;;表示结束一个内部case,代表break.
模式2 )
命令2
;;
esac
#等价于switch语句---
switch(int VAR) //输入VAR是整型!!
{
case var1(对应于模式1) :
do something;
break;
case var2(对应于模式2):
do something;
break;
default :
break;
}
1) case取值后面必须为单词 in;每一模式必须以右括号结束
2) 取值可以为变量或常数。匹配发现取值符合某一模式后,其后的所有命令开始执行,直到;;
3) 模式
模式匹配 | 作用说明 |
---|---|
* | 表示任意字符(字符串) |
? | 表示任意单字符 |
[..] | 表示类或范围中任意字符 |
- 4) 重要说明
//【1】范围case -----------------------------
case val in
a|b|c)
echo "[ ]"
;;
//--等价于->
switch(var){
case a :
case b :
case c :
printf("[ ]");
break;
}
//【2】 *来实现default功能 -----------------------------
case val in
。。。。
*)
echo "default"
;;
//--等价于->
switch(var){
。。。。。
default :
printf("default");
break;
}
- case 的要点
a) 条件处理的是字符串
b) 每一个分支以“;;”作为结束
c) 条件分支一esac结束
d) 通配符*,?,[]
- 实例—————-
通过read从键盘读入一个字符串,如果输入的是数字,如果范围在1~3,进入相应的处理分支,如果输入E或e ,屏幕输出一行:“EXIT!”,如果是其他字符,那么输出:“非法输入+输入的字符串”
#脚本
#!/bin/bash
echo "please input str:\n"
read STR
case $STR in
1|2|3)
echo "your select: $STR"
;;
y|Y)
echo "you agree"
;;
E|e)
echo "exit!"
exit
;;
*)
echo "invalid input:$STR"
;;
esac
#运行结果
jianliu@ubuntu:~/aa$ ./test.sh
please input str:\n
e
exit!
jianliu@ubuntu:~/aa$ ./test.sh
please input str:\n
2
your select: 2
jianliu@ubuntu:~/aa$ ./test.sh y
please input str:\n
y
you agree
4. for 循环
- 语法格式
#该命令在/etc/profile中
#for循环一般格式
for 变量名 in 列表
do
命令1
命令2
done
当变量值在列表里,for循环即执行依次所有命令,使用变量名访问列表中取值。
命令可为任何有效的shell命令和语句。变量名为任意单词。
- in 列表用法是可选择,如果不用它,for循环使用命令行的位置参数。
- in 列表可以包含替换、字符串和文件名
—-实例测试————-
jianliu@ubuntu:~/aa$ cat test.sh
#!/bin/bash
for i in 1 2 3 4 5
do
echo $i
done
jianliu@ubuntu:~/aa$ ./test.sh
1
2
3
4
5
#留心观察输出结果的区别!!!!!!!
jianliu@ubuntu:~/aa$ cat test.sh
#!/bin/bash
echo "test 1"
for i in "aa bb cc dd"
do
echo $i
done
echo "test 2"
for i in aaa bbb ccc ddd
do
echo $i
done
jianliu@ubuntu:~/aa$ ./test.sh
test 1
aa bb cc dd
test 2
aaa
bbb
ccc
ddd
#注意 in后为 命令 反引号--------------------
jianliu@ubuntu:~/aa$ cat test.sh
#!/bin/bash
for loop in `cat test.sh`
do
echo $loop
done
#注意:打印文件内容按照 行+空格 为一行
jianliu@ubuntu:~/aa$ ./test.sh
#!/bin/bash
for
loop
in
`cat
test.sh`
do
echo
$loop
done
#如果in后没有语句,此时语句等价于: in $@ -------------
jianliu@ubuntu:~/aa$ cat test.sh
#!/bin/bash
#for_noion
i=1
for param
do echo "param #$i is $param"
i=$[$i+1]
done
jianliu@ubuntu:~/aa$ ./test.sh aa bbb ccc
param #1 is aa
param #2 is bbb
param #3 is ccc
5. until 循环
#语法格式 until循环格式
until [条件]
do
命令1
命令2
done
#例子 test.sh
#!/bin/bash
VAR=0
until [ $VAR -gt 90 ]
do
echo $VAR
sleep 1
let VAR+=5
done
jianliu@ubuntu:~/aa$ ./test.sh
0
5
10
15
20
25
30
35
40
45
50
55
60
65
70
75
80
85
90
- 条件可以为任意测试条件,测试发生在循环末尾,因此循环至少执行一次
#脚本文件 循环等待直到指定文件exe.app能够被执行,停止程序
#!/bin/bash
until [ -x exe.app ]
do
sleep 2
echo " file exe.app can not be executed!,wait..."
done
echo "now this file can be executed!"
jianliu@ubuntu:~/aa$ ls -l
total 52
-rw-rw-r-- 1 jianliu jianliu 0 Oct 10 05:26 exe.app
jianliu@ubuntu:~/aa$ nohup ./test.sh &
[1] 3963
#查看所有任务(test.sh脚本在后台执行)
jianliu@ubuntu:~/aa$ jobs
[1]+ Running nohup ./test.sh &
jianliu@ubuntu:~/aa$ chmod a+x exe.app #改变exe.app的可执行位标志
#test.sh脚本执行完成。
jianliu@ubuntu:~/aa$ jobs
[1]+ Done nohup ./test.sh
6. while 循环
#语法格式
while 命令 (可以是一个命令也可以是多个,做条件测试)
do
命令1
命令2
...
done
- 注:在while和do之间虽然通常是一个命令,但可以放几个命令。
命令通常用作测试条件。
#输入名称,直到按下Ctrl+d按键,结束。
#!/bin/bash
echo "ctrl+d quit"
while echo -n "please enter name:"; read Name
do
echo "yeah,i got your name: $Name"
done
jianliu@ubuntu:~/aa$ ./test.sh
ctrl+d quit
please enter name:kangkang
yeah,i got your name: kangkang
please enter name:bingbing
yeah,i got your name: bingbing
#从文本name.txt中读取每一行信息,输出到终端显示。
jianliu@ubuntu:~/aa$ cat test.sh
#!/bin/bash
while read LINE
do
echo $LINE
done < names.txt
#------------------------------------------------------
jianliu@ubuntu:~/aa$ ./test.sh
kangkang
bingbing
licaiting
wuhaoao
wanboa
dianfeng
kb536
#!!----错误写法----
#!/bin/bash
#这样写是不对的 ,需要把<name.txt 放在 while循环后面
while read LINE < names.txt
do
echo $LINE
done
- 备注:如果从文件中读入量
<filename
要放到done后.
7. break 和 continue
break [n]
退出循环
如果是在一个嵌入循环里,可以指定n来跳出循环个数
continue
跳出循环步
注意:continue命令类似于break命令,只有一点重要差别,它不会跳出循环,只是跳出这个循环步
总结:break跳出 continue跳过
jianliu@ubuntu:~/aa$ ./test.sh
Enter any num[1...5:]3
you enter a num between 1 and 5
Enter any num[1...5:]7
wrong num, bye
jianliu@ubuntu:~/aa$ cat ./test.sh
#!/bin/bash
while : #死循环
do
echo -n "Enter any num[1...5:]"
read num
case $num in
1|2|3|4|5)
echo "you enter a num between 1 and 5"
;;
*)
echo "wrong num, bye"
break; #如果不加这一句,while就永远退不出去!!!!!
;;
esac
done
#---------------------------------------------------------------
jianliu@ubuntu:~/aa$ ./test.sh
Enter any num[1...5:]2
you enter a num between 1 and 5
Enter any num[1...5:]3
you enter a num between 1 and 5
Enter any num[1...5:]6
wrong num, bye
jianliu@ubuntu:~/aa$
jianliu@ubuntu:~/aa$ cat test.sh
#!/bin/bash
while :
do
echo -n "please input num[1..5]:"
read num
case $num in
1|2|3|4|5)
echo "your slection is $num, between 1 and 5"
;;
*)
echo "wrong num, is continue?(y/n)?"
read IS_CONTINUE
case $IS_CONTINUE in
y|yes|Yes|YES)
continue;
;;
*)
break;
;;
esac
;;
esac
done
#------------------------------------------------------
jianliu@ubuntu:~/aa$ ./test.sh
please input num[1..5]:2
your slection is 2, between 1 and 5
please input num[1..5]:3
your slection is 3, between 1 and 5
please input num[1..5]:5
your slection is 5, between 1 and 5
please input num[1..5]:7
wrong num, is continue?(y/n)?
n
jianliu@ubuntu:~/aa$ ./test.sh
please input num[1..5]:2
your slection is 2, between 1 and 5
please input num[1..5]:3
your slection is 3, between 1 and 5
please input num[1..5]:6
wrong num, is continue?(y/n)?
y
please input num[1..5]:7
wrong num, is continue?(y/n)?
n
jianliu@ubuntu:~/aa$