分类: LINUX
2008-11-30 14:19:44
shell是用户和Linux操作系统之间的接口,它是命令语言、命令解释程序及程序设计语言的统称。用户在提示符下输入的命令都由shell先加以解释,然后再传给linux核心。Shell的另一个重要特性是它自身就是一个解释型的程序设计语言,shell程序设计语言支持函数、变量、数组和程序控制结构等。Linux中有多种shell,如ash、bash、csh等,其中默认的是bash,因此这里我们就学习一下bash外壳下的shell程序设计。
首先我们用vi编写一个简单的shell程序first.sh。首先输入以下命令:
# vi first.sh |
然后,在VI界面下输入以下程序:
#! /bin/bash # My first shell script # clear echo “Hello,everybody!” |
程序first的功能就是清屏并且显示字符串“Hello,everybody!”。在shell程序中,如果以“#!”开头,则“#!”后面所跟的字符串就是所使用的外壳的绝对路径名,第一行表明在此程序中我们使用的是bash外壳。另外,由“#”开始的行为注释行。Clear的作用是清屏,echo的作用是显示字符串,这些命令的作用和在命令提示符下输入时的作用是一样的。
要执行刚才我们的first.sh程序,有三种方法:
(1)将shell程序作为sh命令的输入,具体如下:
# sh first.sh |
(2)利用输入重定向,具体如下:
# bash |
(3)使用chmod命令使first.sh成为可执行的,然后直接执行。
# chmod a+x first.sh # first.sh |
shell程序设计语言的变量类型很简单,只有字符型变量,即所有变量的取值都是一个字符串。
(1)shell变量定义的规则
给变量赋值的方法非常简单,就是在变量名后跟着等号和变量值。例如,想要把5赋给变量count,则使用如下的命令:
# count=5 |
注意,在等号的两边不能有空格。要读取变量的值,可以使用符号$,例如要显示count的值,可以使用如下命令:
# echo $count |
(2)位置变量和其他系统变量
位置变量用来存储shell程序后面所跟的参数。第一个参数存储在变量1中,第二个参数存储在变量2中,依次类推。这些变量为系统保留变量,所以你不能为这些变量赋值。同样,你可以使用$来读取这些变量的值。例如,你可以编写一个外壳程序reverse,执行过程中它有两个变量。输出时,将两个变量的位置颠倒。
#! /bin/bash #program reverse # echo "$2" "$1" |
在命令提示符下执行此外壳程序:
# reverse hello byebye |
其输出如下:
byebye hello |
除了位置变量以外,还有其他的一些系统变量,下面分别加以说明:
有些变量在启动外壳时就已经存在于系统中,你可以使用这些系统变量,并且可以赋予新值:
$HOME 用户自己的目录。
$PATH 执行命令时所搜寻的目录。
$TZ 时区。
$MAILCHECK 每隔多少秒检查是否有新的邮件。
$PS1 在外壳命令行的提示符。
$PS2 当命令尚未打完时,外壳要求再输入时的提示符。
有些变量在执行外壳程序时系统就设置好了,并且你不能加以修改:
$# 存储外壳程序中命令行参数的个数。
$? 存储上一个执行命令的返回值。
$0 存储外壳程序的程序名。
$* 存储外壳程序的所有参数。
“$@” 存储所有命令行输入的参数,分别表示为(“$1”、“$2”)。
$$ 存储外壳程序的P I D。
$! 存储上一个后台执行命令的P I D。
shell也和其他高级程序设计语言一样,能够提供用来控制程序执行流程的命令,用户可以用这些命令建立非常复杂的程序。
(1)test或[]命令
test或[]命令是最常用的一个测试命令,用于测试后面的表达式的值是否为“真”,其格式为test expression或[expression]。Test命令可以和多种系统运算符一起使用。这些运算符可以分为四类:整数运算符、字符串运算符、文件运算符和逻辑运算符。
整数运算符:
test int1 -eq int2 如果int1和int2相等,则返回真。
test int1 -ge int2 如果int1大于等于int2,则返回真。
test int1 -gt int2 如果int1大于int2,则返回真。
test int1 -le int2 如果int1小于等于int2,则返回真。
test int1 -lt int2 如果int1小于int2,则返回真。
test int1 -ne int2 如果int1 不等于int2,则返回真。
字符串运算符:
test str1 = str2 如果str1和str2相同,则返回真。
test str1 != str2 如果str1和str2不相同,则返回真。
test str 如果str不为空,则返回真。
test -n str 如果str的长度大于零,则返回真。
test -z str 如果str的长度等于零,则返回真。
文件运算符:
test -d filename 如果filename为目录,则返回真。
test -f filename 如果filename为普通的文件,则返回真。
test -r filename 如果filename可读,则返回真。
test -s filename 如果filename的长度大于零,则返回真。
test -w filename 如果filename可写,则返回真。
test -x filename 如果filename可执行,则返回真。
逻辑运算符:
test ! expr 如果expr为假,则返回真。
test expr1 -a expr2 如果expr1和expr2同时为真,则返回真。
test expr1 -o expr2 如果expr1或expr2有一个为真,则返回真。
(2)if表达式
bash、pdksh和tcsh都支持嵌套的if...then...else表达式。bash的if表达式如下:
if [expression] then commands elif [expression2] then commands else commands fi |
elif和else在if表达式中均为可选部分。elif是else if的缩写。只有在if表达式和任何在它之前的elif表达式都为假时,才执行elif。fi关键字表示if表达式的结束。
(3)case表达式
case表达式允许你从几种情况中选择一种情况执行。Shell程序中的case表达式的功能要比Pascal或C语言的case或switch语句的功能稍强。这是因为在外壳中,你可以使用case表达式比较带有通配符的字符串,而在Pascal 和C语言中你只能比较枚举类型和整数类型的值。bash的c a s e表达式如下:
Case string1 in str1) commands;; str2) commands;; *) commands;; esac |
在此,将string1和str1、str2比较。如果str1和str2中的任何一个和strings1相符合,则它下面的命令一直到两个分号(;;)将被执行。如果str1和str2中没有和strings1相符合的,则星号(*)下面的语句被执行。星号是缺省的case条件,因为它和任何字符串都匹配。
(4)for表达式
在外壳bash下的shell程序设计中有两种使用 for 语句的表达式:
第一种形式是:
for var1 in list do commands done |
在此形式时,对在list中的每一项,for语句都执行一次。list可以是包括几个单词的、由空格分隔开的变量,也可以是直接输入的几个值。每执行一次循环, var1都被赋予list中的当前值,直到最后一个为止。
第二种形式是:
for var1 do statements done |
使用这种形式时,对变量var1中的每一项,for语句都执行一次。此时,shell程序假定变量var1中包含外壳程序在命令行的所有位置参数。
(5)while表达式
while语句是另一种循环语句。当一个给定的条件为真时,则一直循环执行下面的语句直到条件为假。在bash环境下,使用while语句的表达式为:
while expression do statements done |
下面是在bash外壳中while语句的一个例子。程序列出所带的所有参数,以及他们的位置号,其中shift命令用来将命令行参数左移一个位置。
#! /bin/bash #program test_while # count=1 while [-n "$*"] do echo "This is parameter number $count $1" shift count='expr $count+1' done |
(6)unitl表达式
until语句的作用和while语句基本一样,只是当给定的条件为假时,执行until语句。until语句在bash中的写法为:
until expression do commands done |
让我们用until语句重写上面的例子:
#! /bin/bash #program test_until # count=1 until [-z "$*"] do echo "This is parameter number $count $1" shift count='expr $count+1' done |
在应用中,until语句不是很常用,因为until语句可以用while语句重写。
(7)子函数
shell程序语言可以定义自己的函数,就像在C或其他语言中一样。使用函数的最大好处就是程序更为清晰可读。下面是如何在bash中创建一个函数:
fname() { shell commands } |
使用函数时,只须输入以下的命令:
Fname parm1 parm2 parm3… |
你可以传递任何数目的参数给一个子函数,子函数将会把这些参数视为位置参数。
#bash –选项 程序名 |
选项含义:
-e 如果一个命令失败就立即退出。
-n 读入命令,但不执行。
-u 置换时把未设置的变量看成出错。
-v 当读入shell输入行时把它们显示出来。
-x 执行命令时把命令和它们的参数显示出来。
调试shell程序的主要方法是利用shell命令解释程序的“-v”或“-x”选项来跟踪程序的执行。“-v”选项使程序在执行过程中,将它读入的每一条命令行都显示出来。而“-x”选项使shell在执行过程中,把它执行的每一条命令在行首用一个“+”加上命令名显示出来,并且把每一个变量和该变量的值也显示出来。
除了使用shell的“-v”和“-x”选项外,还可以在shell程序内部采取一些辅助调试的措施。例如,可以在shell程序的一些关键
shell是一种解释执行的语言,可以利用bash命令解释程序的选项来调试程序,其调试格式为:
#bash –选项 程序名 |
选项含义:
-e 如果一个命令失败就立即退出。
-n 读入命令,但不执行。
-u 置换时把未设置的变量看成出错。
-v 当读入shell输入行时把它们显示出来。
-x 执行命令时把命令和它们的参数显示出来。
调试shell程序的主要方法是利用shell命令解释程序的“-v”或“-x”选项来跟踪程序的执行。“-v”选项使程序在执行过程中,将它读入的每一条命令行都显示出来。而“-x”选项使shell在执行过程中,把它执行的每一条命令在行首用一个“+”加上命令名显示出来,并且把每一个变量和该变量的值也显示出来。
除了使用shell的“-v”和“-x”选项外,还可以在shell程序内部采取一些辅助调试的措施。例如,可以在shell程序的一些关键地方使用echo命令,把必要的信息显示出来,它的作用相当于C语言的printf语句。这样就可以知道程序目前的状态和运行到什么地方出错了。