第 5讲 shell编程
5.1 shell概述
5.2 shell变量
5.3 shell的特殊字符
5.4 shell的控制结构
5.5 shell应用实例
5.6 小结
习题
shell是一种命令语言,同时又是一种程序
设计语言。
shell的语言处理能力,使得用户能够方便
地定义各种变量、参数,并使用各种控制语
句编写复杂的命令程序完成多种工作。
本课介绍 shell,shell程序设计语言,shell
的运行环境及 shell程序的实例。
5.1 shell概述
5.1.1 什么是 shell
shell是一种命令解释程序 (命令解释器 ),shell解
释用户输入的命令行,提交系统内核处理,并将结果
返回给用户。与 Linux命令一样都是实用程序,但两者
又有区别。一旦用户注册到系统后,shell就被系统装
入内存,并一直运行到用户退出系统之止;而一般命
令仅当被调用时,才由系统装入内存执行。
shell本身也是一种可编程的程序设计语言。用
shell写的程序 (shell脚本 )相当于 dos/windows下的批处
理文件,它可以简单到只有一条命令,也可以复杂到
包括大量循环、条件语句、数学运算、控制结构,也
可以是介于两者之间的程序。
5.1.2 shell程序语言的特点
shell允许通过编程来完成复杂的功能处理,但
其作为语言与高级语言相比较具有不同的特点:
(1) shell是解释性的,多数高级语言是编译性的;
(2) shell语言与高级语言处理的对象不同;
(3) shell与系统有密切的关系;
(4) shell易编写、调试、灵活性较强,但速度低;
(5) shell作为命令级语言,命令组合功能很强。
5.1.3 bash的特点
shell有两种主要语法类型,Bourne shell和 C
shell,彼此不兼容。 Bourne shell家族,sh ksh bash
psh zsh; C shell家族,csh tcsh。
其中 bash和 zsh在不同程度上支持 csh 的语法。
这里,我们再着重介绍一下 bash的特点:
(1) 自动补全功能
假设要输入的命令很长,或者命令后面要给的
文件名很长。这个时候只要按一个 Tab键,bash就会
在可能的命令或文件名里面找寻匹配的命令,找到
的话就会自动帮你补齐。
(2) 命令行编辑程序
bash的命令行编辑是在提示符下,可对未执行
的命令字符任意地修改。
(3) 命令历史 (command history)
所谓的命令历史就是把曾经输入过的命令记录
起来,方便日后的查询与使用。只要按向上键就可
以调出前一个命令,再按一次向上键就可以调出更
前一个命令,依此类推,用向下键可以回到下个命
令,所以用上、下键就可以选择以前输入过的命令。
5.1.4 Shell程序的创建与执行
? 用任一文本编辑器创建 shell文件 (xxx)
(例如,gedit xxx)
? 将 shell文件改为可执行文件
(例如,$chmod u+x xxx)
? 执行 shell文件
(例如,$./ xxx)
5.1.5 Shell程序示例
? 以 test运行“附件”中“文本编辑器”程序 gedit
? 在新建空白文档中输入如下内容:
date
pwd
cd,.
? 保存文件到 / home/test /xxx 中
? 修改文件权限,运行“系统工具”中“终端”,输
入:
chmod u+x xxx <Enter>
? 输入,/xxx <Enter>
5.2 shell变量
5.2.1 shell变量描述
shell实际上是基于字符串的程序设计语言,但也有变
量。 shell变量能够而且只能存储正文字符串,即它
只有一种类型的变量即串变量。但从赋值的形式上
看,则可以分成四种类型的变量或变量形式。变量
的名字必须以字母或下划线开头,可以包括字母、
数字和下划线。
5.2.2 用户自定义变量
用户自定义变量语法格式,name=string,赋值号,=”
两边不允许有空白符。
例:
nodehost=beijing.UUCP
path=/bin:/usr/bin:/etc/bin
count=10
允许多个赋值操作,按从右到左的顺序进行。
例:
$ A=$ B B=abc C=″OK″
$ echo $ A $ B $ C
abc abc OK
当引用一个未设置的变量时,其隐含值为空。
例:
$ echo ″$ mail is path of mailbox″
is path of mailbox
如果用双引号“”将值括起来,则括起来的字符串
允许出现空格、制表符和换行符等特殊字符,而且
允许有变量替换。
例 1:$ MAIL=/var/mail/fk
$ var=″$ MAIL is path of mailbox″
$ echo $ var
/var/mail/fk is path of mailbox
例 2:
$ str=″This is \ n a book″
$ echo $ str
This is
a book
如果用单引号‘’将值括起来,则括起来的字符串
允许出现空格、制表符和换行符的特殊字符,但不
允许有变量替换。
例 3:
$ BOOK=″English book″
$ MSG=′$ BOOK′
$ echo $ MSG
$ BOOK
例 4:
$ msg=′ Today is Sunday′
$ echo $ msg
Today is Sunday
引用变量的值时,可以用花括号 {}将变量名称括起来,
使变量名称与它的后续字符分隔开,如果紧跟在变
量名称后面的字符是字母、数字或下划线时,必须
要使用花括号。
例 5:
$ str=′This is a string′
$ echo ″$ {str}ent test of variables″
This is a stringent test of variables
$ echo ″$ strent test of variables″
test of variables
5.2.3 位置变量
位置变量顾名思义是与变量所在位置有关的变量,
这是一种特殊的变量。当一个 shell过程被调用时,
shell隐含地为它建立一系列的位置变量。这种位置
变量是系统预定义好的,可以直接引用。如命令行
的 shell过程名本身被指定为位置变量$ 0,第一个
命令参数为$ 1,……,第九个命令参数为$ 9。
例:
ls / /bin /etc /usr/bin /dev
$ 0 $ 1 $ 2 $ 3 $ 4 $ 5
5.2.4 环境变量
shell执行环境由一系列环境变量组成,这些变量是由
shell维护和管理的。所有这些变量都可被用户重新
设置,变量名由大写字母或数字组成。
CDPATH 执行 cd命令时使用的搜索路径;
HOME 用户的 home目录;
PATH 寻找命令或可执行文件的搜索路径;
PS1 主命令提示符,默认为“$”;
PS2 从命令提示符,默认为,>”;
TERM 使用的终端类型。
? PS1中可用信息
\$ 用 $作为提示符
\\ 显示 \
\d 显示当前日期
\h 显示主机名
\s 显示 shell名
\t 显示当前时间 (24)
\T 显示当前时间 (12)
\@ 显示当前时间 (AM/PM)
\u 显示用户名
\v 显示 bash的版本
\W 显示当前工作目录
\w 显示当前工作路径
5.2.5 预定义的特殊变量
在 shell中有一组特殊的变量,其变量名和变量值只有
shell本身才可以设置。
“$ #” 记录传递给 shell的自变量个数。
例 1:
myprog a b c 则 $ #的值为 3
例 2:
if test $ # -lt 2
then
echo ″ two or more args required ″
exit
fi
“$?”取最近一次命令执行后的退出状态:执行成功
返回码为 0,执行失败返回码为 1。
例:
$ test -r my-file(假设 my-file文件不可读 )
$ echo$?
1
“$$”记录当前 shell的进程号。
5.3 shell中特殊字符
在 shell中所使用的许多特殊符号也可为其他目的所
使用,包括 通配符,转义符、单引号和双引号。
1,通配符
* 匹配任何字符串,包括空字符串;
? 匹配任何单个字符;
[,,-,!] 按照范围、列表或不匹配等形式匹配指定
的字符;
\ 转意符,使元字符失去其特殊的含义。
例:
[ a-d,x,y] 匹配字符 a,b,c,d,x,y;
z* 匹配以字符 z开始的任何字符串;
x?y 匹配以 x开始、以 y结束、中间为任何单个字
符的字符串;
[ !Z] 匹配不为 Z的单个字符。
通配符作为文件扩展名的使用
例:
[ a-f] * 匹配字符 a到字符 f开头的文件名,如 abc,
d2,e3.c,f.dat;
*z 匹配以字符 z结尾的任何字符串,如 win.z,
core.zz,a-c-5z;
rc?.d 匹配以 rc开始、以,d结束、中间为任何单个
字符的文件名,如 rc0.d,rc2.d,rcS.d;
*[ !o] 匹配不以 o结尾的文件名。
$ back.sh
Enter your name,john
Hello john
2,单引号 (??)
使用单引号消除被括在单引号中的所有特殊字符的
含义,即单引号表示内容照原样不动。
例 1:
$ echo ′type a $ * please′
type a $ * please
例 2,在指定的目录中,查找名字为 *.zh 或 $,sh文
件。
$ cat test.sh
grep ′*.zh | $,sh′ $ 1
3,双引号 (“”)
使用双引号能消除被括在双引号中的大部分特殊字
符的含义,不能消除的字符有:$,`, ″,\。
例 1:$ echo ″ Type a \$ *,please ″
Type a $ *,please
例 2:
vdate= ″`date` is the system maintenance time ! ″
例 3,$ cat share-file
mkdir /tmp/fk
chmod 755 /tmp/fk
cp ″$ @″ /tmp/fk
chmod 777 /tmp/fk/*
4 反撇号 (``)
当一个字符串被括在反撇号,`,中时,该字符串将
作为命令被 shell解释执行,即用命令的执行结果替
换这个字符串本身。要注意反撇号与单引号的区别。
例 1:$ now=′date′
$ echo $ now
date
$ now=`date`
$ echo $ now
1998年 10月 28日 星期三 17时 51分 56秒
CST
例 2:$ count=10
$ count=`expr $ count+1`
$ echo $ count
11
5,转义符 (\ )
使用转义符消除单个字符的特殊含义,即将紧跟在
转义符后面的单个字符按字符本身的实际含义解释。
例:转义符具有续行功能
$ cat back.sh
echo ″Enter your name,\\ c″
read name
echo Hello $ name
这些控制字串是:
\ b 退格
\ c 显示后不换行
\ f 在终端上屏幕的开始处显示
\ n 换行
\ r 回车
\ t 制表符
\ v 垂直制表符
\ 反斜杠
6,管道的概念
管道:是一个命令的标准输出与另一个命令的标准
输入之间的连接,不经过任何中间文件;
管道线:是由管道操作符分隔的一个命令序列,最
简单的管道线是一个简单命令;
管道操作符:用符号,|”表示。
例:
w|wc -l
ps aux|grep ftp
& 表示前面的管道线在后台 (异步 )执行。
例 1,四个管道线构成一个命令表
ls -l /tmp /root
w|wc -l
ps
例 2,与例 1等价
ls -l /tmp /root ; w|wc -l ; ps
例 3:
sys-account &
7,输入、输出重定向符
使用标准改向符进行重定向 (改向 )
< 输入改向
<< 追加输入改向
> 输出改向
>> 追加输出改向
使用标准文件描述字进行重定向 (改向 )
在 Linux系统中,定义了用于输入、输出的标准文件,
其文件描述字 0为进程的标准输入、文件描述字 1为
标准输出、文件描述字 2为标准错误输出。
标准错误输出的改向 (>,>>)
格式为:
command 2 >file
command 2 >>file
例 1,将 myfile1作为 sort的输入。
sort <myfile1
例 2,将 date的输出转向到 myfile2文件中。
date >myfile2
例 3,将 ls \|l的输出追加到 myfile3文件中。
ls -l>>myfile3
例 4:将错误输出改向到 err-file文件。
$ myprog 2>err-file
例 5:将标准输出和错误输出改向 out文件。
$ myprog >out 2>>out
$ myprog >out 2>>&1
5.4 shell的控制结构
5.4.1 条件与 test命令
在程序设计语言中,作出决策的结构称为条件。在
高级语言中决策的作出是依赖于基本运算的结果;
在 shell语言中,作出决策所依赖的条件是所执行命
令的“出口状态”。
当 shell命令或程序执行成功时,它返回一个“零”出
口状态 (即$?为零 );如果执行的命令或程序出错
时,则返回一个“非零”的出口状态 (即$?不为
零 )。
除了一般命令的出口状态外,UNIX还提供了两个命
令 true和 false的出口状态。 true的出口状态为零;
而 false的出口状态为非零。 shell将 true和 false命令
作为恒真和恒假条件使用。
例,判断所给出的参数是否为一个目录。
$ cat check.dir
test -d $ 1 && echo ″ $ 1 is a dictory ″ && exit 0
echo ″ $ 1 is not a dictroy ″
exit 1
在上例中,使用了 exit命令。它是一个 shell的内部命
令,用于终止 shell程序的执行。该命令可带一个定
义出口状态值的自变量。
例:
exit(0),终止程序的执行,并返回零值;
exit(1)或 exit(x),终止程序的执行,并返回非零值;
将命令返回零出口状态称为返回“真值”;
将命令返回非零出口状态称为返回“假值”。
1,test命令
test命令是 shell程序设计的条件判断中最常用的测试
命令,它有两种等价的格式:
test expression或[ expression] (注意:[ ]中的空
格 )
其中 expression就是要测试的条件。如果 test计算
expression的结果为真,则返回“零”出口状态,
否则返回“非零”出口状态。 test命令可用于对字
符串、整数及文件进行各类测试。
2,test字符串测试表达式
例 1,两个字符串进行比较
$ user=smith
$ test ″$ user″= smith
$ echo $?
0
$ test ″$ user″ = tom
$ echo $?
1
例 2,带有空格的字符串比较
$ month=″January ″
$ test ″$ month″ = January
$ echo $?
1
$ test $ month = January
$ echo $?
0
注意,shell在处理变量时,遇到有双引号将保留其
内容,而省略双引号时,将滤去空格。
例 3,带有空格的字符串比较
$ a=″testing string″
$ test ″$ a″ = ″testing string″
$ echo $?
0
$ test $ a = ″testing string″
test,unknown operator string
shell处理变量 $ a 时,将其进行变量替换,然后将结
果 (testing string)传递给 test,而 test将 string作为操
作符来处理,因此出错。
例 4,带有空串 (或未设置的字符串比较 )
$ name=
$ test ″$ name″ = smith
$ echo $?
1
$ test $ name = smith
test,argument expected
shell处理变量$ name时,双引号将其括起的内容作
为一个“位置持有者”来保留,并把该值传递给
test,保证处理的正常执行。
例 5,带有空串的字符串比较
$ blanks=″″
$ test $ blanks
$ echo $?
1
$ test ″$ blanks″
$ echo $?
0
shell处理变量$ blanks时,将空格滤去,使其变为空
串传递给 test;而双引号保留,位置持有者”的位
置,其值为一个空格 (空白符 ),传递给 test。
例 6,带有算符的字符串比较
$ symvar=″=″
$ echo ″$ symvar″
=
$ test -z ″$ symvar″
test,argument expected
出错的原因是,=”运算符比,-z”运算符的优先级要
高,因此,test 命令期望在等号之后要有一个自变
量。为避免上述问题发生,可用下面命令形式替换:
$ test x″$ symvar″ = x
$ echo $?
1
3,使用 test测试字符串时要注意的问题
(1) 向 test 传递的各自变量之间必须有空白字符,如
果,=”与任一自变量之间没有空白字符就会产生错
误。
(2) 在使用变量的值替换的自变量上,用双引号括起
来十分必要,以保证 test在变量的值为空时也能接
收到该自变量,这是一种良好的 shell程序设计风格。
(3) 在 test命令的测试中,空格和引号是 shell程序设计
中经常发生错误的焦点,要特别引起注意。
(4) test命令对它的自变量非常讲究,在比较的串中出
现运算符时,要考虑到运算符优先级的问题。
4,test命令可用于整数比较
首先要搞清楚整数比较的两个概念,shell并不区分
放在 shell变量中的值的类型,就变量本身而言,它
存放的仅仅是一组字符串,即 shell只有一种类型的
变量 ——串变量;当使用整数比较操作符时,是
test命令来解释存放在变量中的整数值,而不是
shell。
命令格式为,
test 整数测试表达式
例 1:
$ x1= ″ 005 ″
$ x2= ″ 10″
$ test ″ $ x1 ″ = 5
$ echo $?
1
例 2:
$ test ″ $ x1 ″ -eq 5
$ echo $?
0
例 3:
$ test ″ $ x2 ″ -eq 10
$ echo $?
0
5,test用于文件的测试
test可用于文件各种特性的检查。这些文件的操作符
自然是一原操作符,意味着它们要求其后跟随一个
自变量。在所有的情况中,这个自变量是一个文件
或目录名。常用的文件测试表达式示例如下:
例 1,检查指定的文件是否存在并且可读
test -f /usr/fk/message
例 2,检查指定的文件是否为目录
test -d /usr/src/local/sendmail
例 3,检查指定的出错文件是否为空,如不空则列出
该文件的内容
test -s $ errfile && {echo ″Errors found:″;\
cat $ errfile}
6,表达式的逻辑运算
在实际应用中常需要将多个表达式用逻辑运算符组
合起来,构成比较复杂的条件。逻辑运算符包括:
!, 逻辑非单目运算符,可放置在任何其他 test表
达式之前,求得表达式运算结果的非值。
-a, 逻辑与运算符,执行两个表达式的逻辑与运算,
并且仅当两者都为真时,才返回真值。
-o, 逻辑或运算符,执行两个表达式的逻辑或运算,
并只要当两者之一为真时,就返回真值。
逻辑运算符优先级 (由高到低 ) 的排列顺序如下:
( ) ! -a -o
逻辑运算符优先级要比字符串操作符、数字比较操
作符、文件操作符的优先级低。
例 1,当指定的文件不可读时为真。
test ! -r /usr/fk/message
例 2,当指定的文件均存在,且 message为可读、$
mailfile 指定的文件为普通文件时,返回真。
test -r /usr/fk/message -a -f ″$ mailfile ″
例 3,当变量值大于等于 0并且小于 10时为真。
test ″$ count ″ -ge 0 -a ″$ count ″ -lt 10
例 4,当变量$ a等于 0或者$ b大于 5,并且$ c小于
等于 8时为真。
test \ (″$ a″ -eq 0 -o ″$ b″ -gt 5 \ )-a ″$ c″ -le
8
5.4.2 if结构
1,if的简单结构
格式为,
if command
then
command
command
...
fi
2,if的完整结构
格式为,
if command
then
command
command
...
else
command
command
...
fi
3,if的连用结构
格式 1
if commandthen
commands
else if command
then commands
else
… if command
then commands
fi
...fi
fi
格式 2if command
then commands
elif commandthen
commands
elif…
elif commandsthen
commands
else commands
fi
5.4.3 case结构
格式为,
case value in
pattern1) command
...
command;;
pattern2) command
...
command;;
...
patternn) command
...
command;;
esac
5.4.4 for结构
格式为,
for variable in arg1 arg2,.,argn
do
command
...
command
done
5.4.5 while结构
格式为,
while command
do
command
...
command
done
5.4.6 until结构
格式为,
until command
do
command
...
command
done
5.4.7 循环体中其他命令
1,break命令
格式为,
break或 break n
break是 shell的内部命令,用于在循环体中根据命令
运行的返回条件,直接终止循环体内命令的执行。
当执行 break命令时,控制流从循环体中转移到
done之后的第一条命令上。当执行 break n命令时,
则终止最内层的 n个循环的执行。
2,continue 命令
格式为,
continue或 continue n
continue是 shell的内部命令,用于在循环体中根据命
令运行的返回条件,直接进入下一次循环命令的执
行。当执行 continue命令时,控制流直接转到本循
环体中第一条命令上。当执行 continue n命令时,
则跳过最里层的 n次循环体的执行,即开始第 n个
(从内向外数 ) 循环的下一个循环过程。
5.5 shell 程序实例 -shell菜单程序
1.程序功能描述
编写一个 shell程序,使用 shell编写一个菜单,分
别实现列出以下内容:( 1)目录内容、( 2)切换目
录、( 3)创建文件、( 4)编辑文件、( 5)删除文件
的功能。在此例中将用到循环语句 until、分支语句
case、输入输出语句 read和 echo。
2.建立 shell程序 menu如下
#!/bin/sh
until
echo "(1)List you selected directory"
echo "(2)Change to you selected directory"
echo "(3)Creat a new file"
echo "(4)Edit you selected file"
echo "(5)Remove you selected file"
echo "(6)Exit Menu"
read input
test $input -eq 6
do
case $input in
1) ls;;
2) echo "Enter target directory:"
read dir
cd $dir;;
3) echo "Enter a file name:"
read file
touch $file;;
4) echo "Enter a file name:"
read file
vi $file;;
5) echo "Enter a file name:"
read file
rm $file;;
*) echo "Please selected 1\2\3\4\5\6 " ;;
esac
done
5.6 小结
本章主要介绍了什么是 shell,shell变量,shell
命令以及 shell 语言控制结构,并着重讲述了如何使用
shell语言编写 shell程序。大家要充分理解 shell变量,
通过编写 shell程序并运行,来理解 shell程序在整个
Linux系统所起的巨大作用。
编写 shell程序:用户输入一个参数,程序判断
这个参数的字符类型
作业