Shell编程简介

shell编程-shell编程简介
2007年08月17日 星期五 下午 05:17

介绍shell编程
目标:
完成这一章,你能做以下事情:
写出简单的shell程序
通过环境变量传递参数给shell程序
通过位置参数传递参数给shell程序
使用特殊shell变量,*和#
使用shift和read命令
1.1 shell编程概述
shell程序是一个包含UNIX命令的普通文件.
这个文件的许可权限至少应该为可读和可执行.
在shell提示符下键入文件名就可执行shell程序.
shell程序可以通过三种方式接受数据:
-环境变量
-命令行参数
-用户的输入
shell是一个命令解释器,它会解释并执行命令提示符下输入的命令.但是,你可能想要多次执行一组命令,shell提供了一种功能,让你将这组命令存放在一个文件中,然后你可以象unix系统提供的其他程序一样执行这个文件,这个命令文件就叫做shell程序或者shell脚本.当你运行这个文件,它会象你在命令行输入这些命令一样地执行这些命令.为了让shell能读取并且执行你的shell程序,shell脚本的文件权限必须被设置为可读和可执行.为了让shell可以找到你的程序,你可以选择输入完全路径名,或者将这个脚本的路径放在于你的PATH环境变量指定的路径列表中.许多的用户会在他们的HOME目录下创建一个bin目录来存放他们自己开发的script,然后将$HOME/bin加入到他们的PATH环境变量中.你可以写出非常复杂的shell脚本,因为shell脚本支持变量,命令行参数,交互式输入,tests(判断)),branches(分支),和loops(循环)等复杂的结构.
1.2 shell程序举例
$ cat myprog
#this is the program myprog
date
ls –F
$ myprog
要创建一个shell程序,考虑进行以下步骤:
$ vi myprog 一个包含shell命令的程序.
#this is the program myprog
date
ls –F
$ chmod +x myprog 增加文件的执行模式
$ myprog
Thu Jul 11 11:10 EDT 1994
F1 f2 memo/ myprog*
首先使用一个文本编辑器创建一个shell程序myprog.在程序执行之前,这个文件必须被赋予可执行的权限.然后在命令提示符下输入这个程序名,如上例所示,当myprog执行的时候,一个子shell会被创建.这个子shell会从shell程序文件myprog读取输入而不是从命令行读取输入,这个shell中的每个命令的执行都会创建一个子shell.一旦所有的命令都被执行,所有的子shell会中止,然后会返回到原始的父shell.
Shell程序中的注释:
推荐在shell程序中提供注释语句来注明程序的内容.注释由一个#符号开始,Shell不会去执行任何在#之后的语句.#能够出现在命令行的任何位置.
注意:你不可以给shell程序取名为test因为test是一个内部的shell命令.
1.3 传递数据给shell程序
$ color = lavender
$ cat color1
echo you are now running program: color1
echo the value of the variable color is : $color
$ chmod +x color1
$ color1
you ar now running program : color1
the value of the variable color is :
$ export color
$ color1
you are now running program : color1
the value of the variable color is : lavender
传递数据给shell脚本的一种方法就是通过环境.在上例中,本地变量color被赋值为lavender,然后创建了shell程序color1;然后更改为可执行权限;然后这个shell程序被执行,color1脚本的意图是显示color变量的值,但是由于color是一个本地变量,属于父shell私有的,运行color1产生的子shell不能识别这个变量,因此不能打印出它的值,而当color被输出到环境中就可以被子shell读取.
同样,由于shell进程不能够更改父进程的环境,对一个子进程中的环境变量重新赋值不会影响到父进程环境中的值.如以下的shell脚本中的color2.
echo The original value of the variable color is $color
ech0 This program will set the value of color to amber
color=amber
echo The value of color is now $color
echo When your program concludes,display the value of the color variable
观察在你设置了color的值后有什么变化.输出这个变量,然后执行color2:
$ export color=lavender
$ echo $color
lanvender
$ color2
The original value of the variable color is lavender
The program will set the value of color to amber
The value of volor is now amber
When your progam concludes, display the value of the color variable,
$ echo $color
lanvender
1.4 shell 程序的参数
命令行:
$ sh_program arg1 arg2 . . . argx
$0 $1 $2 .... $X
例子:
$ cat color3
echo you are now running program: $0
echo The value of command line argument /#1 is: $1
echo The value of command line argument /#2 is : $2
$ chmod +x color3
$ color3 red green
You are now running program: color3
The value of command line argument #1 is : red
The value of command line argument #2 is: green
大多数的UNIX系统命令可以接收命令行参数,这些参数通常告诉命令它将要操作的文件或目录(cp f1 f2),另外指定的参数扩展命令的能力(ls –l),或者提供文本字符串(banner hi there).
命令行参数对shell程序同样有效,使用这种方式传送信息给你的程序十分方便.通过开发一个接收命令行参数的程序,你可以传递文件或者目录命令名给你的程序处理,就像你运行UNIX系统命令一样,你也可以定义命令行选项来让命令行使用shell程序额外的功能.
在shell程序中的命令行参数与参数在命令行的位置相关,这样的参数被称为位置参数,因为对每一个特殊变量的赋值依靠一这些参数在命令行中的位置,变量的变量名对应变量在命令行中的位置,因此这些特殊的变量名为数字0,1,2等,一直到最后的参数被传递,变量名的存取也通过同样的方法,在名字前面加上$ 符号,因此,为了存取你的shell程序中的命令行参数,你可以应用$0,$1,$2等等.在$9以后,必须使用括号:$(10),$(11),否则,shell会将$10看成是$1后面跟一个0.而$0会一直保存程序或命令的名字
1.4 shell程序的参数(继续)
以下的shell程序会安装一个程序,这个程序作为一个命令行参数被安装到你的bin目录:首先创建程序my_install,注意目录$HOME/bin应该预先存在.
$ cat > my_install
echo $0 will install $1 to your bin directory
chmod +x $1
mv $1 $HOME/bin
echo Installation of $1 is complete
ctrl + d
$ chmod +x my_intalll
$ my_install color3
my_install will install color3 to your bin directory
Installation of color3 is complete
$
这个例子中,程序指明第一个命令行参数为一个文件名,然后加上执行权限,然后移动到你当前目录下的bin目录下.
记住UNIX系统的惯例是存贮程序在bin的目录下.你也许想要在你的HOME目录下创建一个bin目录,在这个目录下你可以存储你的程序文件,记住要将你的bin目录放在PATH环境变量中,这样shell才会找到你的程序.
1.5 一些特殊shell变量- #和*
# 命令行参数的数量
* 完全的参数字符串
例子:
$ cat color4
echo There are $# comand line argument
echo They are $*
ehco The first command line argument is $1
$ chmod +x color4
$ color4 red green yellow blue
They are 4 command line arguments
They are red green yellow blue
The first command line argument is red
$
至今为止我们看到的shell程序都不是很灵活,如color3需要输入两个正确的参数而my_install只需要一个.通常在创建一个接收命令行参数的shell程序的时候,你想要用户输入一个参数的变量号码.你同时要程序执行成功,不管用户键入1个参数或是20个参数.当处理变量参数列表的时候,特殊shell变量会提供你许多的灵活性.通过$#你可以知道有多少参数已经被输入,通过$*可以存取全部的参数列表,而不管参数的数量.请注意参数($0)不在$*这个参数列表里.
每一个命令行参数都是互相独立的,你可以通过$*集中检索这些参数,也可以通过$1,$2,$3等等来独立的检索这些参数.
1.5 一些特殊的shell变量-#和*(继续)
一个可以接收多个命令行参数的安装程序的例子:
$ cat > my_install2
echo $0 will install $# files to your bin directory
echo The files to be installed are : $*
chmod +x $*
mv $* $HOME/bin
echo Installaton is complete
ctril + d
$ chmod +x my_install2
$ my_install2 color1 color2
my_intall2 will install 2 files to your bin directory
The files to be installed are: color1,color2
Intallaiton is complete
这个安装程序更加灵活,如果你有多个文件要安装,你仅需要执行这个程序一次,只要一次输入多个名字即可.
非常重要的是:如果你计划传递整个参数的字符串给一个命令,这个命令必须能够接收多个参数.
在以下的脚本中,用户提供一个目录名作为一个命令行参数.程序会更改到指定的目录,显示当前的位置,并且列出内容.
$ cat list_dir
cd $*
echo You are in the $(pwd) directory
echo The contents of the directory are:
ls –F
$ list_dir dir1 dir2 dir3
sh: cd: bad argument count
由于cd命令不能同时进入到多个目录中,这个程序执行会出错.
1.6 shift 命令
向左移动所有的在*中的字符串n个位置
#的数目减少n个(n的默认值是1)
语法:shift [n]
例子:
$ cat color5
orig_args=$*
echo There are $# command line arguments
echo They are $*
echo Shifting two arguments
shift 2
echo There are $# comand line arguments
echo They are $*
echo Shifting two arguments
shift 2; final_args=$*
echo Original arguments are: $orig_args
echo Final arguments are: $final_args
shift命令会重新分配命令行参数对应位置参数,在shift n以后,所有的*中的参数会向左移动n个位置.同时$#会减n.默认的n为1.Shift命令不会影响到参数0的位置.一旦你完成一次移动,被移出命令行的参数会丢失.如果你想在你的程序中引用这个参数,你需要在执行shift之前存贮这个参数到一个变量中.
Shift命令可以用于:存取一组参数的位置,例如一系列的x,y的坐标
从命令行删除命令选项,假定选项在参数之前.
例子:
$ color5 red green yellow orange black
There are 6 command line arguments
They are red green yellow blue orange black
Shifting two arguments
There are 4 command line arguments
They are yellow blue orange black
Shiftging two arguments
Original arguments are: red green yellow blue orange black
Final argument are : orange black
$
1.7 read 命令
语法:
read variable [variable......]
例子:
$ cat color6
echo This program prompts for user input
echo "please enter your favorite two colors -> /c"
read color_a color_b
echo The colors you entered are: $color_b $color_a
$ chmod +x color6
$ color6
This program prompts for user input
Please enter your favorite two colors -> red blue
The colors you entered are: blue red
$ color6
This program prompts for user input
Please enter you favorite two colors -> red blue tan
The color you enterd are :blue tan red
如果使用命令行参数传递信息进程序,在命令执行之前用户必须知道正确的语法.有一种情况,你想要在用户执行程序的时候提示他输入这些参数.read命令就是用来在程序执行的时候收集终端键入的信息.
通常会使用echo命令来给用户一个提示,让他知道程序正在等待一些输入,同时通知用户应该输入的类型.因此,每一个read命令应该在echo命令后面.
read命令会给出一个变量名的列表,用户在提示符下输入会给这些变量赋值(变量之间以空格分隔).如果read命令定义的变量比输入的词要多,多出的变量会被赋空值.如果用户输入的词要比变量多,剩余的数据会赋给列表中的最后一个变量.
一旦被赋值,你就可以象其他的shell变量一样存取这些变量.
注意:不要混淆位置参数和变量read.位置参数在命令被激活时直接在命令行中使用,而read命令给变量赋值是在程序执行之中,用户响应输入的提示而给变量赋值.
1.7 read命令(继续)
以下例子提示用户输入要被安装的文件名:
$ cat > my_install3
echo $0 will install files into your bin directory
echo "Enter the names of the files -> /c"
read filenames
mv $filenames $HOME/bin
echo Instllation is complete
ctrl + d
$ chmod +x my_install13
$ my_install13
my_install13 will install files into your bin directory
Enter the names of the files -> f1 f2
Installaton is complete
这个安装脚本会提示用户输入需要chmod并移动到$HOME/bin的文件的文件名.这个程序给用户更多的关于应该输入数据情况的指引.而不像install2中用户必须在命令行中提供文件名,用户使用程序不需要特殊的语法,程序让用户确切地知道要输入什么.所有的输入的文件名都会被赋值给变量filenames.
1.8 另外的技术
#号开始的文档为注释部分.
sh shell_program argumetns
shell_program 的属性可以不是可执行的.
shell_program 必须是可读的.
sh –x shell_program arguments
每一行在被执行前被打印出来.
在调试程序时有用处.
在shell程序中,#符号的意思是后面是一段注释,而shell会自动忽略#符号以后直到一个回车符号为止的所有字符.
执行一个shell程序的另外一种方法是:
sh shell_program arguments
这种方式激活一个子shell并且指定这个子shell为执行这个程序的命令解释器.这个程序文件的属性不一定必须为可执行.这种方式的用途在:你正在在一种shell下工作,同时想要执行用其他shell命令语言写的shell程序十分有用.
你也可以在你的shell程序的第一行前加入! /usr/bin/ shell_name来指定命令行解释器,这样如果你当前正在POSIX shell下工作,但是想要执行一个C shell的脚本,你的C shell程序的第一行应该为:
#!/usr/bin/csh
虽然shell程序没有调试器,命令:
sh –x shell_program arguments
会在执行每一行时,先在屏幕上打印出shell程序的每一行.这允许你看到shell如何进行文件名产生,变量替代,和命令替代.这个选项对发现打字错误十分有帮助.
Shell编程-分支语句(1)
目标:
完成这一章,你将能够作以下事情:
描述条件分支语句中返回值的作用.
使用test命令来分析一个命令的返回值.
在shell程序中使用if和case结构.
1.返回值
shell变量" "中保存上一个被执行命令的返回值:
0: 命令成功地执行(真)
非零: 命令由于出现错误而被终止(假)
例子:
$ true $ false
$ echo $ $ echo $
0 1
$ ls $ cp
$ echo $ Usage: cp f1 f2
0 cp [-r] f1 ....fn d1
$ echo $ $echo $
0 1
$echo $
0
UNIX操作系统的所有命令在结束的时候都会产生一个返回值.这个返回值通常被用来判断命令是正常结束(返回0)还是发生了错误(返回非零值).通过返回的非零值还可以看出发生的是什么错误.例如,语法错误通常返回1,true命令返回的就是0,而false命令返回的是1.
大多数的shell程序中的判断语句都是通过分析这个返回值来进行流程控制的.shell中定义了一个特殊的变量" "用来保存上一个命令结束后的返回值.
你可以通过以下方式来观察前一个命令的返回值:
echo $
当你执行一个条件判断(小于,大于,等于)的时候,返回值会指明这个条件是否为真(返回0)或者为假(返回非零).
条件判断语句会在下几节中讲述.
2.test 命令
语法:
test expression 或者 [expression]
test命令对表达式进行测试,并且设置返回值.
表达式的值 返回值
true 0
false 非零(通常为1)
test命令能够测试的对象有:
整数
字符串
文件
test命令被用来评估表达式并且产生返回值.它用参数组成逻辑表达式并且对表达式的返回值进行评估,test命令不会产生标准输出,你必须必须通过返回值来判断test命令的结果,如果表达式为真,返回值会为0,如果表达式为假,返回值为1.
test命令可以被单独使用,然后你能够看到返回值,但它用的最多的还是在if和while结构中用来提供条件流程控制.
test命令的也可以用[expression]来代替.这种方式可以提高可读性,特别是在处理数字或者字符串的时候.
注意:在"["和"]"符号的周围必须要有空格.
3.test命令之数字test
语法:
[ number relation number ] 通过关系运算符来对数字进行比较
关系运算符:
-lt 小于
-le 小于或者等于
-gt 大于
-ge 大于或者等于
-eq 等于
-ne 不等于
例子(假设X=3):
$ [ "$X" -lt 7] $ [ "$X" -gt 7]
$ echo $ $ echo $
0 1
test命令能被用于比较两个整数之间的数字关系,通常用[.....]语法来调用.test命令的返回值就能说明这个条件为真还是为假.
当test一个变量的值的时候,你应该防止变量不要为空值,例如:
$ [ $XX -eq 3]
sh: test:argument expected
如果变量XX在前面没有被赋值,XX的值会是NULL.当shell执行变量替代的时候,shell会试图执行如下语句:
[ -eg 3]
而这个语句不是一个完整的test语句,并且会导致一个语法错误.解决这个问题的一个简单的方法就是在被测试的变量的周围加上引号.
[ "$XX" -eq 3]
当shell执行变量替代的时候,shell会试图执行如下语句:
["" -eq 3]
这会确保至少有一个NULL值作为一个参数提供给这个test命令使用.
注意:作为一个通用的规则,你应该在所有的$变量加上双引号来避免shell发生不正确的变量的替代.
4.test命令-字符串test
语法:
[ string1 = string2] 判断字符串是否相等
[ string1 !=string2] 判断字符串是否不等
例子;
$ X=abc $ X=abc
$ [ "$X" = "abc"] $ ["$X" != "abc"]
$ echo $ $ echo $
0 1
test命令也能够用来计较两个字符串是否相等.
[...] 语法通常用作字符串的比较.你已经看到在[]周围必须要有空格,同时在操作符周围也必须要有空格存在.
字符串操作包括:
string1 = string2 如果string1等于string2就为真
string1 != string2 如果string1不等于string2就为真
-z string 如果string的长度为0就为真
-n string 如果string的长度为非零就为真
string 如果string的长度为非零就为真
为了防止变量中包含空白字符,这里引号同样也能够保护字符串的test,,例如:
$ X="yes we will"
$ [ $X=yes] 会导致一个语法错误
shell会解释这个语句为[yes we will = yes ]
$ [ "$x" = yes ] 正确的语法
shell会解释这个语句为:[ "yes we will" = yes ]
在执行数字比较的时候,shell会将所有的参数当成是数字,在执行字符串比较的时候,shell会把所有的参数当成是字符串.如下例所示:
$ X=03
$ Y=3
$ [ "$X" -eq "$Y" ] 比较数字03和数字3
$ echo $
0 为真,因为它们是相等的数字
$ [ "$X" = "$Y" ] 比较字符串"03"和字符串"3"
$ echo $
1 为假,因为它们是不相同的字符串
5.test命令- 文件比较
语法:
test -option filename 通过选项对文件进行test
例子:
$ test -f funfile
$ echo $
0
$ test -d funfile
$ echo $
1
shell提供的一个有用的test特性是可以用它来test文件的特征,例如文件类型和许可权限.例如:
$ test -f filename
如果文件存在并且是一个普通文件(不是目录或者设备文件),会返回真(0).
test -s filename
如果文件存在并且其字节数大于0,会返回真(0).
其它还有许多有用的文件test方式,比如:
-r file 如果文件存在并且是可读的时候为真
-w file 如果文件存在并且是可写的时候为真
-x file 如果文件存在并且是可执行的时候为真
-d directory 目录存在并且是个目录的时候为真
6.test命令-其他操作符
语法:
-o OR
-a AND
/( /) GROUPING
例子:
$ [ "$ANS" = y -o "ANS' = Y ]
$ [ "$NUM -gt 10 -a "$NUM" -lt 20 ]
$ test -s file -a -r file
注意:()前面必须要用斜杠.
使用Boolean操作符可以同时测试多个条件.
例子:
$ [ "$ANS" = y -o "$ANS" = Y ]
$ [ "$NUM" -gt 10 -a "$NUM" -lt 20 ]
$ test -s file -a -r file -a -x file
NOT操作符(!)被用作连接其他的操作符,特别是在文件test的时候用的很普遍.在!操作符和其他的操作符之间必须要有空格,例如:
test ! -d file
能够用来代替
test -f file -o -c file -o -b file ....
括号被用来对操作符进行分组,但是在shell中括号还有一个特殊的意义就是优先运算的意义.因此,括号前面必须使用/符号来忽略其原有含义.
以下的命令验证:有两个命令行参数,并且第一个命令行参数是一个-m ,并且最后一个命令行参数是一个目录或者是一个字节数大于0的文件:
[ /( $# = 2 /) -a /( "$1" = "-m" /) -a /( -d "$2" -o -s "$2" /) ]
7.exit命令
语法:
exit [arg]
例子:
$ cat exit_test
echo exiting program now
exit 99
$ exit_test
exiting_program now
$ echo $
99
exit命令结束当前shell程序的执行并且设置返回值.通常0被用来说明正常结束,而非0值用来说明一个错误的条件.如果没有特别指明返回值,返回值将被设置为exit命令上一个命令的返回值.
shell编程-分支语句(2)
8.if语句
语法:(用于单向判断分支)
if
list A
then
list B
fi
例子:
if
test -s funfile
then
echo funfile exists
fi
echo hello
if 结构是一种基于命令返回值的的流程控制方式.如果测试命令的返回值为0,一个指定的命令列表就会被执行,如果用于判断的命令返回值为非0,指定命令列表会被忽略而不被执行.
上例中表明了if结构的一个通用的格式:每一个命令列表由一个或者多个UNIX系统的shell命令组成,每个命令之间用回车符或者分号分隔,list A中最后被执行的命令决定if语句的结果.
if结构执行的过程如下所示:
1.list A命令被执行.
2.如果list A中的最后一个命令的返回值为0(真),执行list B中的命令,然后继续执行fi以后的命令.
3.如果list A中的最后一个命令的返回值为非0(假),跳到fi并且继续执行fi以后的命令.
test命令通常被用作流程控制,它可以使用任何的UNIX命令,因为所有的UNIX命令都产生一个返回值,以下的例子可以说明:
if
grep kingkong /etc/passwd > /dev/null
then
echo found kingkong
fi
if结构也能在程序出错的时候提供流程控制.如下例所示:
if
[ $# -ne 3 ]
then
echo Incorrect syntax
echo Usage: cmd arg1 arg2 arg3
exit 99
fi
9.if-else 结构
语法:(用在多分支选择的情况)
if
list A
then
list B
else
list C
fi
例子:
if [ "$X" -lt 10 ]
then
echo X is less than 10
else
echo X is not less than 10
fi
if-else结构让你能够在控制命令的返回值为0的情况下执行一系列的命令,或者在控制命令的返回值为非0的情况下执行另外一系列的命令.
这种情况下if结构的执行过程是:
1.执行list A中的命令.
2.如果在list A中最后一个命令的返回值是0(真),执行list B中的命令,然后继续执行fi以后的命令.
3.如果list A中最后一个命令的返回值为非0(假),执行list C中的命令,然后执行fi以后的命令.
注意在list C中可以包含任何的UNIX命令,其中也包括if.例如:
if
[ "$X" -lt 10 ]
then
echo X is less than 10
else
if
[ "$X" -gt 10 ]
then
echo X is greater than 10
else
echo X is equal to 10
fi
fi
注意:每一个if必须要有一个fi来结束.
10.case结构
语法:(多路分支)
case word in
patterm1) list A
;;
pattern2) list B
;;
patternN) list N
;;
esac
例子:
case $ANS in
yes) echo O.K
;;
no) echo no go
;;
esac
if-else结构也能支持多路的分支,但是当有两个或者三个分支的之后,程序会变得十分难以阅读.case结构提供了实现多路分支的一种更方便的方法.分支选择是顺序地对一个word与提供的参数之间的比较结果.这些比较是是严格的基于字符串的对比.当一个匹配成功的时候,对应的命令就会被执行.每个命令的列表都以两个分号结束.在完成了相关的比较之后,程序会在esac之后继续执行下去.
word典型的情况下是指向一个shell变量.
pattern的组成格式和文件名的生成原则是一致的.
以下是一些pattern允许的特殊的字符:
* 匹配任何字符串和字符包括空字符
匹配任何单个的字符.
[...] 匹配任何一个括号出现中的字符
另外|字符的意义是OR.
注意:在这个结构中的右括号和分号是必须的.
case结构通常被用于菜单选择或者是需要对几个用户输入选项作出选择的时候.
12.shell编程 - 分支:总结
返回值 每一个程序的返回值 - echo $
数字test [ "$num1" -lt "$num2" ]
字符串test [ $string1 = $string2 ]
文件test test -f filename
exit n 终止程序的允许并且设置返回值
if case word in
command listA pattern1) command list
then ;;
command listB pattern2) command list
else ;;
command listC *) command list
fi ;;
esac
执行那个语句基于listA中最后一条 字符串word会与每一个pattern比较
命令的返回值
shell编程之循环语句(1)
目标:
完成这一章,你将能够作以下事情:
使用while语句在条件为真的时候重复地执行一段代码.
使用until语句重复执行一段代码直到条件为真.
使用交互性的for语句进行循环控制.
1.循环的简单介绍
目标: 重复的执行一段命令列表.
控制; 基于一个关键命令的返回值.
三种格式: while ... do ... done
until ... do ... done
for ... do ... done
循环语句让你可以重复执行一个命令列表,而决定是继续循环还是跳出循环是基于一个命令的返回值.test命令常常被用来控制一个循环是否继续.
与分支语句不同的是,在分支语句中开始一个分支语句的关键字和结束一个分支语句的关键字是相反的(if/fi 和case/esac),循环语句由一个关键字和一些条件开始,循环体整个用do/done来包围起来.
2.使用let来进行算术计算
语法:
let expression or (( expression ))
例子:
$ x=10 $ x=12
$ y=2 $ let "x 10 ))
$ let "x = x / (y+1)" $ echo $
$ echo $x $ 0
4 $ if ((x > 10 ))
$ (( x = x + 1 )) > then echo x greater
$ echo $x > else echo x not greater
5 fi
x greater
循环语句通常使用一个增长的数字变量来进行控制.使用let命令,可以在shell脚本中使用算术表达式.这个命令允许使用长的整数运算.在上例中,expression代表一个shell变量的算术表达式和能够被shell识别的操作符,而(( ))可以替let命令.shell能够识别的表达式如下所示:
操作符 描述
- 减去
! 逻辑相反
* / % 乘,除,余数
+ - 加,减
= 关系比较
== != 等于不等于
= 赋值
括号能够被用作改变表达式中计算的顺序,就像在
let "x=x/(y+1)"
中一样
注意双引号被用来忽略括号的特殊含义.同样如果你希望使用空格来分隔操作符和操作符的时候,就必须使用双引号,或者(( ))语句:
let " x = x + (y / 2)" 或者(( x= x+ (y / 2) ))
当使用逻辑和关系操作符,(!,=,,++,~=),的时候,shell会返回一个代码变量, 会反映结果是真还是假,再一次说明,必须使用双引号来防止shell将大于和小于运算符当作I/O重定向.
3.while语句
重复执行循环体,直到条件为真
语法:
while
list A
do
list B
done
例子:
$ cat test_while
X=1
while (( X do
> echo hello X is $X
> let X=X+1
> done
命令执行的过程如下:
1.list A中的命令被执行.
2.如果list A中的最后一个命令的返回值为0(真),执行list B.
3.回到第一步.
4.如果list A中的最后一个命令的返回值不为0(假),跳到下面done关键字后的第一个命令.
提醒:注意while循环会无穷执行下去,因为有一些循环的控制命令的返回值永远为真.
$ cat while_infinite
while
true
do
echo hello
done
$ while_infinite
hello
hello
.
.
.
ctrl + c
4. while结构举例
例A: 例B
如果ans为yes就重复执行 当有命令行参数时重复执行
ans=yes while (($# != 0 ))
while do
[ "$ans" = yes ] if test -d $1
do then
echo Enter a name echo contents of $1;
read name ls -F $1
echo $name >> file.names fi
echo "Continue " shift
echo Enter yes or no echo There are $# items
read ans echo left on the cmd line
done done
上例是两个while语句的例子,例A提示用户输入,然后对用户的输入进行判断,来决定是否继续执行循环,例子B中,循环会对命令行中每一个参数进行判断,如果参数是一个目录,这个目录中的内容会被显示出来.如果这个参数不是一个目录,程序会跳过.注意shift命令的用法,它允许一个一个存取每一个参数.和while命令一起使用可以使这个循环非常灵活.它不关心参数的个数是1个还是100个,循环会继续执行直到所有的参数都被存取.
注意,如果你希望循环至少执行一次,就必须进行某些设置.例A中会执行循环体至少一次因为ans已经被设为yes.在例B中,如果程序的执行不带任何参数($#等于0),这个循环就一次都不会执行.
5.until语句
重复循环直到条件为真为止.
语法: 例子:
until $ cat test_until
list A X=1
do until (( x > 10 ))
list B do
done echo hello X is $X
let X=X+1
done
$ test_until
hello X is 1
hello X is 2
hello X is 3
.
.
.
hello X is 10
until语句是shell提供的另一种循环机制,它会持续执行命令(list B)直到一个条件为真为止.同while循环类似,条件判断由list A中的最后一条命令的返回值来决定的.
命令的执行过程如下:
1.list A中的命令被执行.
2.如果list A中最后一条命令的返回值为非0(假),执行list B.
3.返回到第一步.
4.如果list A中的最后一条命令的返回值为0(真),跳到done关键字后的第一条命令.
注意:until循环的无穷执行下去,因为有些循环语句中的控制语句的返回值始终为假.
$ x=1
$ until
> [ $ x -eq 0 ]
> do
> echo hello
> done
hello
hello
hello
.
.
.
ctrl + c
6.until的例子
例A 例B
重复执行循环体直到ans为no为止 重复执行循环直到没有命令行参数为止
ans=yes until (( $# == 0 ))
until do
[ "$ans" = no ] if test -d $1
do then
echo Enter a name echo context of $1;
read name ls -F $1
echo $name >> file.names fi
echo "Continue " shift
echo Enter yes or no echo There are $# items
read ans echo left on the cmd line.
done done
上例的结构与while语句中的例子类似,但是使用until语句来.注意在两种语句的test条件的逻辑关系是相反的.
同时请注意用户输入的敏感性由一些轻微的变化.使用while语句,只有用户的输入的字符串为"yes"时循环才会执行,继续执行循环的条件十分严格,使用until语句,循环会在用户使用与no不同的任何字符时都会执行.它对于继续进行循环的条件不太严格,你也许希望在决定那一种结构最符合你的要求的时候考虑这一特征.
预定义ans变量的值不再是必须的,因为它的值会被初始化为NULL,由于NULL不等于no,test会返回假,而循环会被执行.你仅仅需要将$ans用括号引起来,以免在test语句执行时发生语法错误.
shell编程之循环语句(2)
7.for语句
对列表的每一条目都进行一次循环过程
,每完成一次循环过程就将var赋予列表中下一个条目,直到完成最后一个条目的循环为止
语法: 例子:
for var in list $ cat test_for
do for X in 1 2 3 4 5
list A do
done echo "2 * $X is /c"
let X=X*2
echo $X
done
$ test_for
2 * 1 is 2
2 * 2 is 4
2 * 3 is 6
2 * 4 is 8
2 * 5 is 10
在上例中,关键字为for,in,do和done,var代表一个shell变量的名字,这个变量的赋值会贯穿for循环的执行过程中,list是一串由空格或者tab分割开的字符串,在每一次循环执行都要将一个串赋值给var.
for循环的执行过程如下:
1.shell变量var被设置等于list中的第一个字符.
2.list A中的命令会被执行.
3.shell变量var被设置等于list中下一个字符.
4.list A中的命令被执行.
5.循环会持续执行,直到每一个list中的条目都执行过循环为止.
8.for循环的例子
例A:
$ cat example_A
for NAME in $(grep home /etc/passwd | cut -f1 -d:)
do
mail $NAME < mtg.minutes
echo mailed mtg.minutes to $NAME
done
例B
$ cat example_B
for FILE in *
do
if
test -d $FILE
then
ls -F $FILE
fi
done
for结构是一种非常灵活的循环结构,它能够让循环贯穿任何能产生的列表.使用命令替代可以很容易产生生成列表,就像第一个例子使用管道和过滤器可以产生一个列表.如果你要求多次存取相同的列表,你也许想要将它存储到个文件中.你可以使用cat命令来为你的for循环产生列表,正如下例所示:
$ cat students
user1
user2
user3
user4
$ cat for_student_file_copy
for NAME in $(cat students)
do
cp test.file /home/$NAME
chown $NAME /home/$NAME/test.file
chmod g-w,o-w /home/$NAME/test.file
echo done $NAME
done
$
存取命令行参数
你可以从命令行参数来产生list:
for i in $* 或者 for i
do do
cp $i $HOME/backups cp $i $HOME/backups
done done
9.break,continue,和exit命令
break [n] 中止循环过程的执行,并且跳到下一个命令.
continue [n] 停止循环过程的当前一个反复并且跳到循环中的下一个反复过程的开始部分
exit [n] 停止shell程序的执行,并且将返回值设置为n.
在许多情况下,你可能需要在循环的正常中止条件满足之前放弃一个循环的执行.break和continue命令提供了一种无条件的流程控制,通常用在遇到一个错误的情况下来中止当前的循环.而exit命令用在不能从某种情况下恢复出来而必须中止整个程序的运行的时候.
break命令会中止循环并且将控制权传递到done关键字后面的第一个命令.结果是完全跳出这个循环体而继续执行下面的命令.
continue命令有一点不同.当在程序执行过程中遇到这个命令,就会忽略本次循环中剩余的命令,而将控制权交给循环的顶部.这样,continue命令能让你仅仅中止所有循环中的一个循环过程而继续从当前循环的顶部开始执行.
在while和until循环中,这种处理(continue)会导致在初始列表的开始部分继续执行,在for循环中,会将变量设置为列表中的下一个条目,然后继续执行循环.
exit命令停止执行当前的shell程序,并且根据提供的参数为这个shell程序设置一个返回值,如果没有提供返回值参数,当前的shell程序的返回值会被设置为在exit命令之前执行的命令的返回值.
注意:循环的流程控制在正常的情况下应当是通过设置循环开始部分的条件(while,until),或者是列表中的条目都循环完的(for),的情况来结束循环.而对循环过程进行中断操作仅仅应当在循环执行期间遇到没有规律的或者是错误的条件的时候才应当使用.
10.break和continue的例子
while
true
do
echo "Enter file to remove: /c"
read FILE
if test ! -f $FILE
then
echo $FILE is not a regular file
continue
fi
echo removing $FILE
rm $FILE
break
done

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值