在启动或执行(包括下面我们要讲的shell程序--脚本)过程中可以使用以下一些参数,我们一一说明:
-a 将所有变量输出 -c "string"从string中读取命令 -e 使用非交互式模式 -f 禁止shell文件名产生 -h 定义 -i 交互式模式 -k 为命令的执行设置选项 -n 读取命令但不执行 -r 受限模式 -s 命令从标准输入读取 -t 执行一命令,然后退出shell -u 在替换时,使用未设置的变量将会出错 -v 显示shell的输入行 -x 跟踪模式,显示执行的命令
许多模式可以组合起来用,您可以试试了,但-ei好象不行,你说why呢?
使用set可以设置或取消shell的选项来改变shell环境。打开选项用"-",关闭选项用"+",多数unix允许打开或关闭a、f、e、h、k、n、 u、v和x选项。若显示Shell中已经设置的选项,执行:
$echo $-
Bsh中每个用户的home目录下都有一个.profile文件,可以修改该文件来修改shell环境。为了增加一个可执行文件的路径(例如/ice_walk/bin), 可以把下面代码加入.profile中
PATH=$PATH:/ice_walk/bin;exprot PATH
.profile中shell的环境变量意思如下:
CDPATH 执行cd命令时使用的搜索路径 HOME 用户的home目录 IFS 内部的域分割符,一般为空格符、制表符、或换行符 MAIL 指定特定文件(信箱)的路径,有UNIX邮件系统使用 PATH 寻找命令的搜索路径(同dos的config.sys的 path) PS1 主命令提示符,默认是"$" PS2 从命令提示符,默认是">" TERM 使用终端类型
2>Bsh里特殊字符及其含义
在Bsh中有一组非字母字符。这些字符的用途分为四类:作为特殊变量名、产生文件名、数据或程序控制以及引用和逃逸字符控制。他们 可以让用户在Shell中使用最少的代码完成复杂的任务。
*> Shell变量名使用的特殊字符 $# 传送给命令Shell的参数序号 $- 在Shell启动或使用set命令时提供选项 $? 上一条命令执行后返回的值 $$ 当前shell的进程号 $! 上一个子进程的进程号 $@ 所有的参数,每个都用双括号括起 $* 所有参数,用双括号括起 $n 位置参数值,n表示位置 $0 当前shell名 *>产生文件名的特殊字符 包括"*","?","[]",上面讲过,不再多说。 *>数据或程序控制使用的特殊字符 >(file) 输出重定向到文件中(没有文件则创建,有则覆盖) >>(file) 输出重定向到文件中(没有则创建,有则追加到文件尾部) <(file) 输入重定向到文件 ; 命令分割符 | 管道符 & 后台运行(例如:sleep 10 &) ` ` 命令替换,重定向一条命令的输出作为另一命令的参数 *>对于引用或逃逸的特殊字符
Bsh用单引号' '和双引号" "将特殊字符或由空白分隔的字引用起来组成一个简单的数据串.使用单引号和双引号的区别是双引号中的内容可进行参数和变量替换.逃逸字符也一样.
$echo "$HOME $PATH" 结果显示$/u/ice_walk/bin:/etc:/usr/bin 而$echo '$HOME $PATH' 结果显示$HOME $PATH
shell的逃逸符是一个"\",表示其后的字符不具有特殊的含义或不是shell的函数
$echo \$HOME $PATH 结果显$$HOME /bin:/etc:/usr/bin:
$SUN=sun $echo ${SUN}day
在应用shell变量时候,可以在变量名字两边$后面加上{},以更加清楚的显示给shell,哪个是真正的变量,以实现字符串的合并等功能。
结果显示:sunday(注意不能echo $SUNday,因为SUNday变量没定义,读者试下执行结果) 用户也可以在命令行上同时对多个变量赋值,赋值语句之间用空格分开:
$X=x Y=y
注意变量赋值是从右到左进行的
$X=$Y Y=y X的值是y $X=z Y=$Z
Y的值是空(变量未赋值时,shell不报错,而是赋值为空)
用户可以使用"unset <变量>"命令清除给变量赋的值
用户使用变量时要在其前面加一"$"符,使变量名被变量值所替换。Bsh可以进行变量的条件替换,即只有某种条件发生时才进行替换。替换条件放在一对大括号{}中,如:
${variable: -value} variable是一变量值,value是变量替换使用的默认值
$echo Hello $UNAME 结果显示:Hello $echo Hello ${UNAME: -there} 结果显示:Hello there $echo $UNAME 结果显示: (空) $UNAME=John $echo Hello ${UNAME: -there} 结果显示:Hello John
可以看出,变量替换时将使用命令行中定义的默认值,但变量的值并没有因此而改变。另外一种替换的方法是不但使用默认值进行替换,而且将默认值赋给该变量。其形式如下:
${variable:=value}
该形式在变量替换后同时把值value符给变量variable。
$echo Hello $UNAME 结果显示:Hello $echo Hello ${UNAME:=there} 结果显示:Hello there $echo $UNAME 结果显示:there $UNAME=John $echo Hello ${UNAME:-there} 结果显示:Hello John
变量替换的值也可以是` `括起来的命令:
$USERDIR={$Mydir: -`pwd`}
第三种变量的替换方法是只有当变量已赋值时才用指定值替换形式:
${variable: +value}
只有变量variable已赋值时,其值才用value替换,否则不进行任何替换,例如:
$ERROPT=A $echo ${ERROPT: +"Error tracking is acitive"} 结果显示:Error tracking is acitive $ERROPT= $echo ${ERROPT: +"Error tracking is acitive"} 结果显示: (空)
我们还可以使用错误检查的条件进行变量替换:
${variable:?message}
当变量variable已设置时,正常替换。否则消息message将送到标准错误输出(若此替换出现在shell程序中,那么该程序将终止)。 例如:
$UNAME= $echo $ {UNAME:?"UNAME HAS NOT BEEN SET"} 结果显示:UNAME HAS NOT BEEN SET
$UNAME=Stephanie $echo $ {UNAME:?"UNAME HAS NOT BEEN SET"}
结果显示:Stephanie 当没有指定message时,shell将显示一条默认的消息,例如:
$UNAME= $echo $ {UNAME:?} 结果显示:sh:UNAME:parameter null or not set
在Shell中使用数据变量
用户可以在Shell中使用数据变量,例如ba.sh程序:
cd/usr/icewalk ls|cpio -o > /dev/fd0
该程序中要备份的目录为一常量,即该程序只能用来备份一个目录。若在该程序中使用变量,则会使其更通用:
workdir=$1 cd $workdir ls * |cpio -o > /dev/fd0
通过这一改变,用户可以使用程序备份变量$workdir指定的目录。例如我们要备份/home/www的内容,只要运行ba.sh /home/www即可实现。(若不明白 $1,下面将详细介绍shell参数的传递,$1代表本sh程序-ba.sh的第一个参数)
用户不能单纯使用"*"做乘法,若输入: $expr 4*5 系统将会报错,因为Shell看到"*"将会首先进行文件名替换。正确形式为: $expr 4 \* 5 结果显示:20 多个算术表达式可以组合在一起,例如: $expr 5 + 7 / 3 结果显示:7 运算次序是先乘除后加减,若要改变运算次序,必须使用"`"号,如: $int=`expr 5 + 7` $expr $int/3 结果显示:4 或者: $expr `expr 5+7`/3 结果显示:4
我们可以用$*变量传递不确定的参数给程序:
$cat >re3.sh cd $workdir cpio -i $* < /dev/fd0 ^d
我们就可以恢复多个文件,例如fname1,fname2,fname3 $re3.sh fname1 fname2 fname3 (以上程序re.sh,re2.sh,re3.sh,假设用户已经chmod了可执行权利)
因为没有赋值的变量可以作为NULL看待,所以若是程序re3.sh在执行时候没赋予参数,那么一个空值将被插入到cpio命令中。该命令将恢复所有保存的文件。
echo命令可以使用一些特殊的逃逸字符进行格式化输出,下面是这些字符及其含义:
\b Backspace \c 显示后不换行 \f 在终端上屏幕的开始处显示 \n 换行 \r 回车 \t 制表符 \v 垂直制表符 \ 反斜框 \0nnn 用1,2或3位8进制整数表示一个ASCII码字符
read语句
Shell程序不但可以通过命令行参数得到输入数据,还可以使用read命令提示用户输入数据,其语法格式为:
read var1 var2... ...varn
当Bsh遇到一个read语句时,在标准输入文件中读取数据直到一个换行符。此时Shell在解释输入行时,不进行文件名或变量的替换,只是简单地删除多余的空格。然后Shell将输入行的第一个字的内容给变量1,第二个给变量2,直到所有变量都赋上值或是输入行为空。若输入行中字的个数超过变量个数,Shell将把输入行中剩余的所有字的内容都赋给最后一个变量。当变量个数多于输入行字的个数时候,多于的变量将赋一个空值。输入行的每一个字是由空格分隔的一个字母和数字组成的字符串。
$read var1 var2 var3 输入:Hello my friend $echo $var1 $var2 $var3 结果显示:Hello my friend $echo $var2 结果显示:my Shell程序中的函数
函数又叫做子程序,可以在程序中的任何地方被调用,其格式如下:
函数名字() { command ... ... command; }
Shell程序的任何地方都可以用命令 "函数名字" 调用,使用函数的好处有两点,一点是使用函数可以把一个复杂的程序化为多个模块,易于管理,符合结构化程序的设计思想,另一个好处是代码的重用。
Shell函数和Shel程序比较相似,它们的区别在于Shell程序在子Shell中运行,而Shell函数在当前Shell中运行。因此,在当前Shell中可以看到Shell函数对变量的修改。在任何Shell中都可以定义函数,包括交互式Shell。
例如:
$dir() {ls -l;}
结果是我们在$后面打dir,其显示结果同ls -l的作用是相同的。该dir函数将一直保留到用户从系统退出,或执行了如下所示的unset命令: $unset dir 下面的例子说明了函数还可以接受位置参数:
$dir(){_ >echo "permission ln owner group file sz last access >ls -l $*; >}
运行 dir a* 看产生什么结果
参数a*传递到dir函数中并且代替了$*
通常Shell程序将在子Shell中执行,该程序对变量的改变只在子Shell中有效而在当前Shell中无效。"."命令可以使Shell程序在当前Shell中执行。用户可以在当前Shell中定义函数和对变量赋值。通常用下面命令来重新初使化.profile对Shell环境的设置。 $ . .profile 由于看到这部分相对简单,我们还是顺便说说trap好了
使用trap命令进行例外处理
用户编写程序在程序运行时可能会发生一些例外情况,比如执行该程序的用户按中断键或使用kill命令,或者控制终端突然与系统断开等。unix系统中的上述情况会使系统向进程发一个信号,通常情况下该信号使进程终止运行。有时侯用户希望进程在接到终止信号时进行一些特殊的操作。若进程在运行时产生一些临时文件,又因接受到的信号而终止。那么该进程产生的临时文件将保留下来。在bsh中,用户可以使用trap命令修改进程接收到终止信号时进行的默认操作。 trap命令格式如下:
trap command_string signals
多数系统中共有15种发给进程的信号,默认情况下大多数信号都会使程序终止。用户最好查阅自己系统的文挡,看看本系统内使用的信号种类。除了信号为9(真正的kill信号)不能使用trap命令外,其他信号所带来的操作都可以用trap命令进行指定。下面是trap命令中经常使用的几种信号:
信号 功能 1 挂起 2 操作中断 15 软终止(kill信号)
若命令串中包含不只一条命令,必须使用引号将整个命令括起来,具体是单引号还是双引号,由用户是否需要变量替换决定。" "替换,' '不替换。
使用下面trap命令可以使程序在接收到挂起、中断或kill信号时,首先把临时文件删除,然后退出:
trap "rm $TEMPDIR/* $$;exit" 1 2 15
在上面例子中,当Shell读取trap命令时,首先对$TEMPDIR和$$进行变量替换,替换之后的命令串将被保存在trap表中,若上例中trap命令使用单引号时,trap命令执行时候,不进行变量替换,而把命令串 rm $TEMPDIR/* $$;exit 放到trap表中,当检测到信号时,程序解释执行trap表中的命令串,此时进行变量替换。前面变量$TEMPDIR和$$的值为执行trap指令时候的值,后一种情况中变量的值为程序接收到信号时候的值,所以 "、'一定要区分仔细。
下面命令的含义为用户按二次中断键后,程序才终止:
trap 'trap 2' 2
一般trap命令中的命令串中几乎都包含exit语句,上面rm的例子若无exit语句,接收到信号rm命令执行完后程序将挂起。但有时用户也需要程序在接到信号后挂起,例如当终端和系统断开后,用户发出挂起信号,并执行空命令,如下:
trap : 1
若用户想取消前trap指令设置的命令串,可以再执行trap命令,在命令中不指定命令串表示接收到信号后进行默认的操作,命令如下: trap 1
|