0
点赞
收藏
分享

微信扫一扫

Shell中的控制语句

 任何复杂结构的程序都可以由顺序、分支、循环三种结构实现。

    Shell中的控制语句主要分为两大部分:一个是条件测试与判断语句,另一个是循环结构的控制语句。

条件控制语句  

1)if语句  

①无分支条件语句:if-then结构

if [condition]

   then

    commands

     ……

 last -command

fi

②二分支条件语句:if-then-else结构

if  [condition]

   then

     true -command

     ……

 last-true-command

else

false-command

last-false-command

fi

③多分支条件语句:if-then-elif结构

if  [conditlon_1]

    then

   command_l

elif [condition_2]

    then  

 command_2

   elif[condition_3]

     then

           command_3

       ……

 else

     command_n      

fi

2) Case语句 Case-in结构。

Case语句的语法为:

case  word  in

pattern-1)patl-listl;;

pattern-2)pat2-list2;;

……  

*)default -list;;

esac

Word是与case中各匹配模式进行比较的变量,Pattern-1、Pattarn-2是匹配模式。每个匹配模式命令的结束用“;;”符表示,类似与C语言中使用的break语句的功能(case结构本身没有break语句)。

     在shell的条件控制语句中可以使用统配符,*”可以匹配任何多个字符的字符串,“?”可以匹配任意单一字符。

例:假设有一个连续运行系统,每当运行中遇到错误时,系统都创建一个错误记录文件errorfile并将错误信息写入其中。而且这个文件是按照错误出现的频率进行更新的。编写一段shell程序,根据errorfile文件产生的特性再生成一个定时错误日志文件,日志文件名为datelog。

#!/bin/sh

#例题checkerr.sh

date>>datelog

if test -r errorfile

   then cat errorfile>>datelog

       rm errorfile

 else echo "No error this hour.">>datelog

fi  

例1:向指定的文件中添加信息。

#!/bin/sh

#filename:append.sh

case  $#  in

   1)cat>>$1;;

   2)cat>>$2<$1;;

   *)echo  ‘usage:append.sh [from] to’ ;;

esac

程序名为append.sh,输入下列命令:

$append.sh file1 或 $append.sh fils1 file2

     $#=1时,程序执行时从标准输入流中获取文本,将接受的内容以添加方式存入文件file1中。

  $#=2时,程序会执行第二条匹配语句,完成将file2的文本增加到file1中的操作。

例2:编写一段shell程序,根据执行时获取的当前时间显示出不同的问候信息。

#!/bin/sh

#例题wh.sh

#case结构

hour=`date +%H`

case $hour in

0[1-9]|1[01])echo “Good morning!”;;

1 [234567])echo “good afternoon!”;;

*)echo “good evening!”;;

esac

if 的独特条件表达式

command      命令执行成功,等于返回0 (比如grep ,找到匹配),执行失败,返回非0 (grep,没找到匹配)。

以多条command或者函数作为if 条件, 以最后一个命令执行的退出状态为其值。


if command  等价于 command+if $?

   if  cat tmp.txt | grep ting1; then

 cat 111-tmp.txt | grep ting1

    if [ $? -eq 0 ]

    then

关系运算


if [  $a = q -o $a = Q  ]


if test $a -gt -1 && test $a -lt 101


if [ $a -gt -1 ] && [ $a -lt 101  ]

if 的独特条件表达式

[[ expr ]] 是bash中真正的条件判断语句,其语法更符合编程习惯 (比如 &&, || 的用法),

      在 [[ ]] 中 故意传字符串给 -eq 也应该像 test 一样报错,但是显然bash实现中直接把非整数的字符串直接转换成了 0 ,任何需要整数,但是提供的确又是其他不能转换成整数的字符串,都变成了0。  

      这应该是bash实现中的没有对 [[ ]] 中 -eq 操作符两边的内容进行检查导致的。

菜单的构造

select var in menu-item;do command; done  

select 表达式是一种bash的扩展应用,尤其擅长于交互式使用。select语句的特征主要有:没有echo指令,自动用1、2、3、4列出菜单、没有 read指令,自动输入、没有赋值指令,自动输入数字后,赋值字符串给变量。

菜单的构造

select var in menu-item;do command; done  

例:利用select语句构造菜单

#!/bin/sh

echo "please input your choice:"

select fruit in "apple" "orange" "banana" "quit"

do

       if [ $fruit = "quit" ]

       then exit

       fi

       echo "your choice is $fruit"

done

循环语句

1)for循环:for-in-done结构

for循环的语法格式为:

for variable  in list-of -values

do command

 ……

    last -command

done

shell扫描list-of-values,将其中的第一个字存在循环变量(variable)中,然后执行do与done之间的命令(即循环体)。再将第二个字保存在循环变量(variable)中并再次执行循环体,依次循环。

注意:List-of-values包含着循环体中命令被执行的次数,同时还要将循环变量中存放的内容一一列出,这是与其他语言的循环语句使用不同的地方。bash支持{n..m}的写法。

例:列出用户注册目录下的cc和work子目录中所有C语言源程序文件。

#!/bin/sh

#显示*.C文件

cd $HOME

for dir in cc work

do echo “….in $dir….”

   cd $dir

    for file in *.[c]

       do ls -l $file

       done

        cd

done

 2) while循环:while-do-done结构

语法结构为:

while [condition]

do

  commands

  …

  last-command

done

 可以把while循环语句看作是for循环和if条件语句的功能组合形式,在完成while循环时,通常首先要执行一个test命令,根据test的执行结果决定下一步循环体是否还要执行。如果test的返回值为真时,执行do-done中的内容;否则不执行循环体并结束循环过程。

注意:在while循环中要设计好condition的出口状态,它应是能够在程序执行中被改变的,否则会出现程序的死循环状况。

例:

#!/bin/sh

#例while循环wh.sh

while[-r abc.c]

     do  

echo ‘before sleep……’

sleep 5

     echo ‘sleep done’

 done

    因为此程序在判定了文件abc.c存在并可读后,就输出“Before sleep.....”,停留5秒后再输出"sleep done",然后反复循环执行这两条输出语句,所以直到文件abc.c被删除或取消了读取权限以前,该程序都不能跳出循环,是一种死循环的过程。  

3)until循环:until-do-done结构  

只要循环条件为假(非0值),就执行循环体。格式如下:

until [condition]

do

  commands

 ……

 last-command

done

     如果在第一次执行时,循环条件就为真,则循环体可能会永远不执行。必须在程序中设置能使条件为“真”的因素(注意:对while来讲是判别条件为“假”,而until是判别条件为真),否则该循环会成为一个无限循环的死循环程序。如果出现这种问题,用户必须用系统的kill命令杀死这个进程以终止循环。  

for语句用来实现循环,还有其他常见3种形式写法:

列表for循环语句

不带列表的for循环语句

类似C语言的for循环语句

1.列表for循环语句,格式如下:

for var in {list}  

do  

  Loop body

done  

如:

for country in {'China','America','England','Japan'}  

do  

      echo $country  

done  

2.不带列表的for循环语句,格式如下:

for var    

do  

  Loop body

done  

如:for argument  

do    

echo "$argument"  

done  


执行:sh test16.sh  1 2 3  

3.类似C语言的for循环语句,格式如下:  for ((expression1;expression2;expression3))  

do  

  Loop body  

done

如:

for ((i=1;i<100;i++))

do

   let "sum+=i"

done

break语句

   break语句用来结束循环,基本语法格式如下:

break n

   break 命令后面的整数n表示要提出n层循环,默认值为1。

continue语句

   continue语句表示不再运行循环体中continue后面的语句,开始下次循环。基本语法格式如下:

 continue n

continue命令后面的整数n表示要提出n层循环,默认值为1。

例:编一个程序,查看指定的用户是否登录到系统上。如果没有,则在他登录时进行报告。

#程序uon:查询用户“***”是否在系统中

until who|grep”$1”>/dev/null      

do

 sleep 30  #等待30秒

done

echo  -e “\07\07$1 is logged on”  #07表示一次蜂鸣声

     #当用户登录时用于提示

exit 0

  程序中只要循环条件为“真”,until循环就终止。如果grep命令未能在who命令送给它的用户列表中发现指定的用户ID,则循环条件保持为假(不为0),并且until循环继续执行循环体的“sleep“指令。  

上例程序运行存在一个问题,如使用者一直没登录,则使用者也无法使用该终端。合理地解决办法是将本程序放后台运行。

$uon lili&   /*后台运行该程序检查用户lili是否登录到系统*/

4583  /*系统显示进程ID*/

$   /*系统显示shell命令提示符,现可以做其他事情了*/

   如果lili登录,系统会用两声蜂鸣和显示信息"lili is on the system”通知使用者lili用户已经登录了。

expr命令

expr命令是对shell变量进行算术运算的操作,因为shell变量都是字符型变量,对这种变量简单的进行四则运算不能达到预期的效果,必须使用expr命令做四则运算。在程序中是将表达式作为一种实参引用的。如:

$count =0  /*首先给变量count赋值*/

$count =count+1  /*试图完成count+l再赋给count的操作*/

$echo $count    /*查看操作后的效果*/

系统显示:0+1

$count =  “`expr $count + 1`”

$echo  $count

系统显示:1

   使用这一命令时为避免出现错误,在命令书写中要将操作数与运算符之间用空格分开,如果运算符是乘号或除号时,对它们要做转义处理,例如,\*,/ \就是表示对符号“*”和“\”的转义。

其他:a=$[$a+1] 即用$[] 来完成算术运算。

   

另外在编写循环语句时,也可以使用break和continue语句来改变for和while循环的执行顺序。它们的引用方法与C语言中的规定相似,即break表示退出当前所在的整个循环。continue表示结束本轮循环,转到下一轮循环的开始。

 其他:

a=$(expr 3 + 4)

b=$( date )

()中写命令


a=$[$a+1] 即用$[] 来完成算术运算。

[]中写算术表达式

let c=12    只能对变量赋数值,字符赋值一律为0

  若需要将标准输入的值存入到变量中,可用read命令.例:

# the read command example

echo “enter you name:\c”

read  name

echo “your name is $name”

read 命令中的参数说明:

read [word1][word2][rest]

存放方式为:第一,第二,其余参数

# test read command,filename:read_test

echo “give me a long sentence:\c”

read word1 word2 rest

echo “$word1\n $word2\n $rest”

echo “end of my act”

运行: $ read_test

         give me a long sentence:

输入:let’s test the read command.

输出:let’s

        test

        the read command

        end of my act

编写shell程序许多时候需要与用户交互,因此输出格式也很重要。几个问题要注意:

1)shell 程序执行可能会有错,若不做重定向都会输出到标准输出上,应注意将不必要的信息输出到垃圾文件中。例:

cp filea  fileb >/dev/null

2) 用echo命令可完成向用户显示信息,例如:

$ echo “Mary had a little lamb”

echo命令也可以实现格式化输出,描述如下。

在echo 命令中可使用的字符及含义:

\b    Backspace(回退一个字符)

\c    显示输出信息后不换行

\f    在终端的屏幕开始处进行显示

\n    换行符

\r     回车符

\t     显示制表符(Tab)

\v     垂直制表符

注:linux中使用这些格式显示时需加“-e”选项。

 shell程序的调试方法

Shell程序是一种解释执行语言,其执行是逐行完成的,当程序中语句有语法错误时,对未执行到的语句,系统并不进行提示。但在编程中通常要对程序的整体正确性进行调试和验证:

1)交互式调试:对命令或语法可先用命令进行验证,然后再引用到shell编程中。

2)在编辑过程中不断调试执行所编辑的程序:UNIX中可以打开多个窗口工作,可以在一个打开的窗口中进行vi的程序编辑,在另一个打开的窗口中执行并观察刚编辑的程序的执行结果,判断是否正确,逐步完成整个程序的调试。

3)使用-v、-x选项对shell程序进行跟踪:

-v—完成详细跟踪,将逐行读入执行的命令,并在标准输出上显示,然后执行此语句,直到有语法错误时停止执行过程。

-x—实际命令运行的跟踪,首先显示经过变量替换后的命令行内容,然后再执行它。  

例:对一个shell程序test.sh进行跟踪的过程如下:

假设,test.sh中只包括两条语句:

date

echo  $PATH

若采用-v选项跟踪时输入命令:

$sh –v test.sh

执行结果为:

date

Fri Aug 8:16:00 Prc 2001

Echo $PATH

/usr/bin:/usr/ucb/bin:/home/chr/bin 

例:编写一个shell程序on.sh,判断指定的用户是否注册,若是则拷贝一个关于用户信息的文件,否则显示一条提示信息。程序如下:

#on.sh

echo “type in your logname :\c”  #\c新行终止符

read user

if  

  grep $user /etc/passwd>/tmp/null

  who –u | grep $user

then

 echo “$user has logged in the system.”

 cp /tmp/null tmp1

 rm /tmp/null

else

 echo “$user has not logged in the system.”

fi  

可能运行结果:

$sh ./on

 type in your logname:chen↙

chen yyt04 Mar 12 14:32 0:03 453

chen has logged in the system.

$cat tmp1

 chen:*:200:50::/usr/chen:/bin/sh

举报

相关推荐

0 条评论