03_shell_控制流结构

版权声明:原创,可以评论,技术交流,转载请标识转载何处,尊重作者 https://blog.csdn.net/WUZHU2017/article/details/82219076

什么是流控制

#!/bin/bash
#创建一个目录
    make /home/wbm/shell/txt
#复制所有txt文件到指定目录 
    cp *.txt /home/wbm/shell/txt
    rm -f *txt

--------------------------------------------
上述脚本会出现问题吗?
如果目录创建失败或成功如何处理
文件拷贝失败如何处理

test 条件测试

有时判断字符串是否相等或检查文件状态或是数字测试等。
Test命令用于测试字符串,文件状态和数字
如果test命令中列出的条件成立,test命令就会退出并返回退出状态码0

==文件状态测试

 格式    test condition    或 [ condition ]

//使用方括号时,要注意在条件两边加上空格!!!!!!!!!!!!

-d     目录               
-s     文件长度大于0、非空
-f     正规文件          
-w     可写
-L     符号链接          
-u     文件有suid位设置
-r     可读              
-x     可执行
-z     字符串为空


hzmct@U-64:/study/linuxtest/day03$ help test
test: test [expr]
    Evaluate conditional expression.

    Exits with a status of 0 (true) or 1 (false) depending on
    the evaluation of EXPR.  Expressions may be unary or binary.  Unary
    expressions are often used to examine the status of a file.  There
    are string operators and numeric comparison operators as well.

    The behavior of test depends on the number of arguments.  Read the
    bash manual page for the complete specification.

    File operators:

      -a FILE        True if file exists.
      -b FILE        True if file is block special.
      -c FILE        True if file is character special.
      -d FILE        True if file is a directory.
      -e FILE        True if file exists.
      -f FILE        True if file exists and is a regular file.
      -g FILE        True if file is set-group-id.
      -h FILE        True if file is a symbolic link.
      -L FILE        True if file is a symbolic link.
      -k FILE        True if file has its `sticky' bit set.
      -p FILE        True if file is a named pipe.
      -r FILE        True if file is readable by you.
      -s FILE        True if file exists and is not empty.
      -S FILE        True if file is a socket.
      -t FD          True if FD is opened on a terminal.
      -u FILE        True if the file is set-user-id.
      -w FILE        True if the file is writable by you.
      -x FILE        True if the file is executable by you.
      -O FILE        True if the file is effectively owned by you.
      -G FILE        True if the file is effectively owned by your group.
      -N FILE        True if the file has been modified since it was last read.

      FILE1 -nt FILE2  True if file1 is newer than file2 (according to
                       modification date).

      FILE1 -ot FILE2  True if file1 is older than file2.

      FILE1 -ef FILE2  True if file1 is a hard link to file2.

    All file operators except -h and -L are acting on the target of a symbolic
    link, not on the symlink itself, if FILE is a symbolic link.

    String operators:

      -z STRING      True if string is empty.

      -n STRING
         STRING      True if string is not empty.

      STRING1 = STRING2
                     True if the strings are equal.
      STRING1 != STRING2
                     True if the strings are not equal.
      STRING1 < STRING2
                     True if STRING1 sorts before STRING2 lexicographically.
      STRING1 > STRING2
                     True if STRING1 sorts after STRING2 lexicographically.

    Other operators:

      -o OPTION      True if the shell option OPTION is enabled.
      -v VAR     True if the shell variable VAR is set
      -R VAR     True if the shell variable VAR is set and is a name reference.
      ! EXPR         True if expr is false.
      EXPR1 -a EXPR2 True if both expr1 AND expr2 are true.
      EXPR1 -o EXPR2 True if either expr1 OR expr2 is true.

      arg1 OP arg2   Arithmetic tests.  OP is one of -eq, -ne,
                     -lt, -le, -gt, or -ge.

    Arithmetic binary operators return true if ARG1 is equal, not-equal,
    less-than, less-than-or-equal, greater-than, or greater-than-or-equal
    than ARG2.

    See the bash manual page bash(1) for the handling of parameters (i.e.
    missing parameters).

    Exit Status:
    Returns success if EXPR evaluates to true; fails if EXPR evaluates to
    false or an invalid argument is given.
//eg1 使用test指令
$ test -d dir
//显示前一个命令的运行状态
$ echo $?
1

//eg2 使用[空格 表达式 空格]
$ [ -w 1 -a -x 2 ]
$ echo $?
1

//eg3  使用脚本
hzmct@U-64:/study/linuxtest/day03$ cat 6testdir.sh 
#!/bin/bash
echo "test 命令使用 方法1"
test -d "mulu"
#显示上一个命令执行是否成功 0表示成功
echo $?
#使用[]运算将表达式包含起来
echo "test命令使用 方法 2 []"
[ -d "mulu" ]
echo $?

==字符串测试

格式如下:
test "string"
test string_operator "string"
test "string" string_operator "string"

[]方法
[ string_operator string ]
[string string_operator string ]
使用方括号时,要注意在条件两边加上空格

测试两个字符是否相等。退出状态变量 $?0表示成功,1表示失败。
操作数string_operator   
=     两个字符串相等
!=    两个字符串不等
-z    空串
-n    非空串


eg
hzmct@U-64:~$ echo $chen

hzmct@U-64:~$ [ -z $chen ]
hzmct@U-64:~$ echo $?
0

eg
hzmct@U-64:~$ aa="123"
hzmct@U-64:~$ bb="456"
hzmct@U-64:~$ [ "$aa"="bb" ]//错误的写法
hzmct@U-64:~$ echo $?
0
//= 两边要有空格!!!
hzmct@U-64:~$ [ "$aa" = "$bb" ]//正确的写法
hzmct@U-64:~$ echo $?
1
hzmct@U-64:~$ [ "$aa" = "$aa" ]
hzmct@U-64:~$ echo $?
0

==测试数值

格式    测试两个数值大小
    "number" numberic_operator "number"
    或者
    [ "number" numberic_operator "number" ]
    numberic_operator可为:
    -eq         数值相等。
    -ne         数值不相等。
    -gt         第一个数大于第二个数。
    -lt         第一个数小于第二个数。
    -le         第一个数小于等于第二个数。
    -ge         第一个数大于等于第二个数。

eg:
hzmct@U-64:~$ a1=10
hzmct@U-64:~$ a2=12
hzmct@U-64:~$ [ "$a1" -eq "13" ]
hzmct@U-64:~$ echo $?
1
hzmct@U-64:~$ [ "$a1" -eq "10" ]
hzmct@U-64:~$ echo $?
0

expr数字运算

expr argument operator argument
加法运算:expr 10 + 10
减法运算:expr 20 - 10
加法运算:expr 10 / 5
乘法运算:expr 10 \* 5

eg
hzmct@U-64:~$ expr 10 + 10
20
hzmct@U-64:~$ expr 10+10  //错误的写法 
10+10

hzmct@U-64:~$ expr 10 * 10
expr: syntax error

//使用乘号时也要用反斜线屏蔽其特殊意义
hzmct@U-64:~$ expr 10 \* 10
100
hzmct@U-64:~$ 


if-then

使用if-then 语句
if command
then 
    command
fi
注意:
    bash shell的if语句会运行if后面的那个命令。如果该命令的退出状态码是0(该命令成功运行),位于then部分的命令就会被执行。如果该命令的退出状态码是其他值, then部分的命令就不会被执行, bash shell会继续执行脚本中的下一个命令。
     fi语句用来表示if-then语句到此结束。

常用的方式
if command; then 
    command
fi

//例子
hzmct@U-64:/study/linuxtest/day03$ cat 7if.sh 
#!/bin/bash
echo "test use 1"
#测试文件是否可写
test -w tmp.txt
if [ $? -eq "0" ];then
    echo -e "success\n"
else
    echo -e  "not success\n"
fi
echo $?
echo "test use 2 [] begin"
 [ -w tmp.txt ]
echo $?

if then else

语法1
if command
then
    command
else
    command
fi

eg
hzmct@U-64:/study/linuxtest/day03$ cat 8ifelse.sh 
#!/bin/bash
if [ "13" -lt "12" ]
then
    echo "yes 13 is less than 12"
else
    echo "NO"
fi

if嵌套

if command1
then
    commands
elif commmand2
then
    commands
fi

eg:检查文件是否为空,若是空文件删除
#!/bin/bash
echo -n "Enter your filename:"
read myfile
#-e 检查文件是否存在
if [ -e $myfile ]; then
        if [ -s $myfile ]; then
        echo "$myfile exist and size greater than zero"
        echo "will not remove this file"
    else
        echo "$myfile exist but size is zero"
        echo "delete empty file ......"
        rm $myfile
    fi
else
    echo "file no exist"
fi


hzmct@U-64:/study/linuxtest/day03$ ./9ifif.sh 
Enter your filename:1
file no exist
hzmct@U-64:/study/linuxtest/day03$ touch 1
hzmct@U-64:/study/linuxtest/day03$ ./9ifif.sh 
Enter your filename:1
1 exist but size is zero
delete empty file ......

if-then的高级特性

bash shell提供了两项可在if-then语句中使用的高级特性:
 用于数学表达式的双括号
 用于高级字符串处理功能的双方括号

==双括号
表达式
(( expression))

expression可以是任意的数学赋值或比较表达式。除了test命令使用的标准数学运算符,
表12-4列出了双括号命令中会用到的其他运算符
val++   后增
val--   后减
++val   先增
--val   先减
!       逻辑求反
~      位求反
**      幂运算
<<      左位移
>>      右位移
&       位布尔和
|       位布尔或
&&      逻辑和
||      逻辑或

hzmct@U-64:~$ echo $((10 ** 2))
100

hzmct@U-64:/study/linuxtest/day03$ cat 10ifshuangkuohao.sh 
#!/bin/bash
#using double parenthesis
var1=10
#不需要将双括号中表达式里的大于号转义。这是双括号命令提供的另一个高级特性
if (( $var1 ** 2 > 90)); then
    (( var2 = $var1 ** 2))
    echo "The square of $var1 is $var2"
fi

==双方括号
双方括号命令提供了针对字符串比较的高级特性。双方括号命令的格式如下:
[[ expression ]]
双方括号里的expression使用了test命令中采用的标准字符串比较。但它提供了test命
令未提供的另一个特性——模式匹配(pattern matching)
说明 :双方括号在bash shell中工作良好。不过要小心,不是所有的shell都支持双方括号。
eg:
hzmct@U-64:/study/linuxtest/day03$ cat 11ifshuangfangkuohao.sh 
#!/bin/bash
#using pattern matching
#
if [[ $USER == r* ]]
then
    echo "Hello $USER"
else
    echo "Sorry, I do not know you"
fi


hzmct@U-64:/study/linuxtest/day03$ USER="rich"
hzmct@U-64:/study/linuxtest/day03$ ./11ifshuangfangkuohao.sh 
Hello rich

    使用了双等号(==)。双等号将右边的字符串(r*)视为一个模式,
并应用模式匹配规则。双方括号命令$USER环境变量进行匹配,看它是否以字母r开头。如果是
的话,比较通过, shell会执行then部分的命令。

case

case variable in
pattern1 | pattern2) commands1;;
pattern3) commands2;;
*) default commands;;
esac


case命令会将指定的变量与不同模式进行比较。如果变量和模式是匹配的,那么shell会执行
为该模式指定的命令。可以通过竖线操作符在一行中分隔出多个模式模式。星号会捕获所有与已
知模式不匹配的值。

hzmct@U-64:/study/linuxtest/day03$ cat 12case.sh 
#!/bin/bash
#looking for a possible value
#
if [ $USER = "rich" ];then
    echo "welcom $USER"
    echo "please enjoy your visit"
elif  [ $USER = "barbara" ];then   
    echo "welcom $USER"
    echo "please enjoy your visit"

elif  [ $USER = "testing" ];then   
    echo "welcom $USER"
    echo "special testing account"
elif  [ $USER = "jessica" ];then   
    echo "Do not forget to logout when you're done"
fi
#case 实现
#using the case command
#
case $USER in
rich | barbara)
    echo "welcom, $USER";;
testing)
    echo "special testing account";;
jessica)
    echo "do not forget to log off when you are done";;
*)
    echo "sorry, you are not allowed here";;
esac

case多选择语句格式:
casein
模式1)
    命令1
    ;;
模式2)
    命令2
    ;;
esac

1)case取值后面必须为单词in;每一模式必须以右括号结束。
2)取值可以为变量或常数。匹配发现取值符合某一模式后,其后的所有命令开始执行,直到;;
3)模式匹配*表示任意字符; ?表示任意单字符; [..]表示类或范围中任意字符

eg:
hzmct@U-64:/study/linuxtest/day03$ cat 13case.sh 
#!/bin/bash
echo -n "enter a number from 1 to 3:"
read num
case $num in
1)
    echo "you select 1"
    ;;

2)
    echo "you select 2"
    ;;
3)
    echo "you select 3"
    ;;
y|Y)
    echo "you select y/Y"
    ;;
*)
    echo " `basename $0` :this is not between 1 and 3">&2
    echo " $0 :this is not between 1 and 3">&2
    exit;
    ;;
esac

循环命令 for

语法格式:
for循环一般格式
for 变量名 in 列表
do 
    命令1
    命令2
done

1 当变量值在列表里,for循环即执行依次所有命令,使用变量名访问列表中取值。
2 命令可为任何有效的shell命令和语句。变量名为任意单词。
3 in列表用法是可选择,如果不用它,for循环使用命令行的位置参数。
4 in列表可以包含替换、字符串和文件名

eg:
#!/bin/bash
#简单遍历
for i in 1 2 3 4 5 
do
    echo $i
done

for i in aaa bbb ccc
do
    echo $i
done
#读取文件
for loop in `cat myfile`
do
    echo $loop
done
#复杂字符的处理
for test in I don\'t know if "this'll" work in "New york"
do
    echo "word:$test"
done


hzmct@U-64:/study/linuxtest/day03$ ./14for.sh 
1
2
3
4
5
aaa
bbb
ccc
11
22
33
word:I
word:don't
word:know
word:if
word:this'll
word:work
word:in
word:New york
#!/bin/sh
i=1
#若不使用循环列表,for循环使用命令行的位置参数
for parm 
do
    echo "parm #$i is $parm"
    i=$i+1
done
结果
hzmct@U-64:/study/linuxtest/day03$ ./15for.sh 11 22 33 44 55
parm #1 is 11
parm #1+1 is 22
parm #1+1+1 is 33
parm #1+1+1+1 is 44
parm #1+1+1+1+1 is 55

until

  • 语法
    until循环格式
    until 条件
    do
    命令1
    命令2
    done
    条件可以为任意测试条件,测试发生在循环末尾,因此循环至少执行一次。
hzmct@U-64:/study/linuxtest/day03$ cat 16until.sh 
#!/bin/bash
#监控分区是否满了,若满了给系统发邮件
part="/dev/sda1"
#awk提取第5列数据 sed 将%替换为空格 g表示全部替换
look_out=`df|grep "$part"|awk '{printf $5}'| sed 's/%//g'`
echo $look_out
until [ "$look_out" -gt 48 ]
do
    echo -e "Filesystem $part is nearly full"| mail root
    look_out=`df|grep "$part"|awk '{print $5}'| sed 's/%//g'`
#每隔1s检查磁盘一次
    sleep 1
done

----------------------------------------------------------
eg2 
//until命令和while命令工作的方式完全相反。 
//until命令要求你指定一个通常返回非零退出状态码的测试命令。
//只有测试命令的退出状态码不为0, bash shell才会执行循环中列出的命令。
//一旦测试命令返回了退出状态码0,循环就结束了
hzmct@U-64:/study/linuxtest/day03$ vim 18until.sh 

  1 #!/bin/bash
  2 #until_mom 加锁文件 -f 判断文件是否存在
  3 until [ ! -f a.lock ]
  4 do
  5     echo "check a.lock exist"
  6     sleep 2
  7 done
  8 echo "you may start another application safety"
-----------------------------------------------------
eg3
hzmct@U-64:/study/linuxtest/day03$ cat 18_1until.sh 
#!/bin/bash
var1=100
until [ $var1 -eq 0 ] 
do
    echo $var1
    var1=$[ $var1 - 25 ]
done


while

while 命令 (可以是一个命令也可以是多个,做条件测试)
do
命令1
命令2

done
注:在while和do之间虽然通常是一个命令,但可以放几个命令。
命令通常用作测试条件

hzmct@U-64:/study/linuxtest/day03$ cat 17while.sh 
#!/bin/bash
#while 的使用
echo "ctrl+d quit"
        while echo -n "please enter your name:";read name
do
    echo "your name:$name"
done

----------------------------------
eg2
hzmct@U-64:/study/linuxtest/day03$ cat 19while_readfile.sh 
#!/bin/bash
#从文件names.txt中按照行读取数据
while read LINE
do
    echo $LINE
#如果从文件中读入变量, <filename 要放到done后
done <names.txt

break 与 continue

break [n]
    退出循环
    如果是在一个嵌入循环里,可以指定n来跳出循环个数
continue
    跳出循环步

注意:continue命令类似于break命令,只有一点重要差别,它不会跳出循环,只是跳出这个循环步
总结:break跳出 continue跳过
#!/bin/bash
while  :
do
    echo -n "Enter any num[1...5]:"
    read num
#嵌套case
    case $num in
    1|2|3|4|5)
        echo "You enter a num between 1 and 5"
        ;;
    *)
        echo "wrong num, bye"
#在处理多个循环时,break命令自动终止你所在的最内层的循环
        break
        ;;
    esac
done
#!/bin/bash
while  :
do
    echo -n "Enter any num[1...5]:"
    read num
#嵌套case
    case $num in
    1|2|3|4|5)
        echo "You enter a num between 1 and 5"
        ;;
    *)
        echo "wrong num, continue (y/n)?:"
        read is_continue
        case $is_continue in
            y|yes|Yes)
                continue
                ;;
            *)
                break
                ;;
        esac
    esac
#!/bin/bash
#测试break n, n指定了要跳出循环层级
#注意双括号的使用:用于计算高级的数学表达式
for (( a=1; a<4; a++ ))
do
    echo "outer loop:$a:"
    for(( b=1;b<100;b++ ))
    do  
        if [ $b -gt 4 ];then
#n指定了要跳出循环层级,默认情况下n=1 表示跳出的是当前循环
#n=2,表示就会停止下一级的外部循环
            break 1
        fi
        echo "  inner loop: $b"
    done
done

break 1 运行结果
这里写图片描述

break 2 运行结果

hzmct@U-64:/study/linuxtest/day03$ ./22break.sh 
outer loop:1:
  inner loop: 1
  inner loop: 2
  inner loop: 3
  inner loop: 4

判断是目录还是文件

#!/bin/bash
for file in ./*
do
#-d 判断文件是否是目录
    if [ -d "$file" ]; then
        echo "$file is a directory"
    else
        echo "$file is a file"
    fi
#for的结果进行排序再输出到文件中
done | sort >output.txt

猜你喜欢

转载自blog.csdn.net/WUZHU2017/article/details/82219076
今日推荐