您的位置:首页 > 运维架构 > Shell

Unix系列shell程序编写从入门到精通(上)

2011-07-04 00:00 288 查看
*Shell 是什么 ?

任何发明都具有供用户使用的界面。
UNIX
供用户使用的界面就是
Shell(DOS

command
熟悉吧,但
UNIX
的要强大的多
)

Shell
为用户提供了输入命令和参数并可得到命令执行结果的环境。

为了不同的需要,
UNIX
提供了不同的
Shell
。现在的
UNIX
大部分都支持
BourneShell
,以下教程就以
BourneShell(Bsh)
为例,一步步的领略
UNIX Shell
的强大功能,占先其强大魅力,达到更方便灵活的管理、应用
UNIX
的目的。

1.UNIX
内核和
Shell
的交互方法

启动
UNIX
时,程序
UNIX(
内核
)
将被调入计算机内存,并一直保留在内存中直到机器关闭。在引导过程中,程序
init
将进入后台运行一直到机器关闭。该程序查询文件
/etc/inittab
,该文件列出了连接终端的各个端口及其特征。当发现一个活动的终端时,
init
程序调用
getty
程序在终端上显示
login
等登陆信息。
(username

passwd)
,在输入密码后,
getty
调用
login
进程,该进程根据文件
/etc/passwd
的内容来验证用户的身份。若用户通过身份验证,
login
进程
把用户的
home
目录设置成当前目录并把控制交给一系列
setup
程序。
setup
程序可以是指定的应用程序,通常
setup
程序
为一个
Shell
程序,如
:/bin/sh

Bourne Shell

command
出来了,呵呵)。

得到控制后,
Shell
程序读取并执行文件
/etc/.profile
以及
.profile
。这两个文件分别建立了系统范围内的和
该用户自己的工作环境。最后
Shell
显示命令提示符,如
$

(
这是以
bsh
为例,若是
csh,

.cshrc,ksh

.kshrc,bash

.bashrc
等等
)


:(
不妨把
/etc/.profile

.profile
看成
DOS

autoexec.bat

config.sys
文件
)


shell
退出时,内核把控制交给
init
程序
,
该程序重新启动自动登陆过程。有两种方法使
shell
退出,一是用户执行
exit
命令,二是
内核
(
例如
root

kill
命令
)
发出一个
kill
命令结束
shell
进程。
shell
退出后,内核回收用户及程序使用的资源。

用户登陆后,用户命令同计算机交互的关系为
:
命令进程
--->Shell
程序
--->UNIX
内核
--->
计算机硬件。当用户输入一个命令,如
$ls, Shell
将定位其可执行文件
/bin/ls
并把其传递给内核执行。内核产生一个新的子进程调用并执行
/bin/ls
。当程序执行完毕后,内核取消
该子进程并把控制交给其父进程,即
Shell
程序。例如执行
:

$ps

该命令将会列出用户正在执行的进程,即
Shell
程序
(
下来详细说说,别急现在
)

ps
程序。若执行
:

$sleep 10 &

$ps

其中第一条命令将产生一个在后台执行的
sleep
子进程。
ps
命令执行时会显示出该子进程。

每当用户执行一条命令时,就会产生一个子进程。该子进程的执行与其父进程或
Shell
完全无关,这样可以使
Shell
去做其他工作。
(Shell
只是把用户的意图告诉内核,然后该干嘛干嘛
:))
现在
windows
有个计划任务
(
在固定的时间,日期自动执行某任务
),
其实
UNIX
很早就有这个功能了,也就是所谓的
Shell
的自动执行。一些
UNIX
资源,如
cron
可以自动执行
Shell
程序而无需用户的参与,
(
这个功能好象在
/var/spool/crotab
目录里
)


Crontab
程序对于系统管理员来说是非常有用的。
Cron
服务用于计划程序在特定时间(月、日、周、时、分)运行。我们以
root

crontab
为例。根用户的
crontab
文件放在
/var/spool/crontab/root
中,其格式如下:

(1)

(2)

(3)

(4)

(5)

(6)

0

*

*

3

/usr/bin/updatedb

1.
分钟
(0-60)

2.
小时
(0-23)

3.

(1-31)

4.

(1-12)

5.
星期
(1-7)

6.
所要运行的程序

2.Shell
的功能和特点

1>
命令行解释

2>
使用保留字

3>
使用
Shell
元字符
(
通配符
)

4>
可处理程序命令

5>
使用输入输出重定向和管道

6>
维护一些变量

7>
运行环境控制

8>
支持
Shell
编程

对于命令行解释就不多说了,就是在
shell
提示符
(
例如
:$,%,#

)
后输入一行
unix
命令,
Shell
将接收用户的输入。

使用保留字
:Shell
有一些具有特殊意义的字,例如在
Shell
脚本中,
do,done,for
等字用来控制循环操作,
if,then
等控制条件操作。
保留字随
Shell
环境的不同而不同。

通配符:
*
匹配任何位置

?
匹配单个字符

[]
匹配的字符范围或列表
例如
:

$ls [a-c]*

将列出以
a-c
范围内字符开头的所有文件

$ls [a,m,t]*

将列出以
e,m

t
开头的所有文件

程序命令
:当用户输入命令后,
Shell
读取环境变量
$path(
一般在用户自己的
.profile
中设置
)
,该变量包含了命令可执行文件可能存在的目录列表。
shell
从这些目录中寻找命令所对应的可执行文件,然后将该文件送给内核执行。

输入输出重定向及管道
:重定向的功能同
DOS
的重定向功能:

>
重定向输出

<
重定向输入

而管道符号,是
unix
功能强大的一个地方
,
符号是一条竖线
:|
,用法
: command 1 | command 2
他的功能是把第一个命令
command 1
执行的结果作为
command 2
的输入传给
command 2
,例如
:

$ls -s|sort -nr|pg

该命令列出当前目录中的所有文件,并把输出送给
sort
命令作为输入,
sort
命令按数字递减的顺序把
ls
的输出排序。然后把排序后的
内容传送给
pg
命令,
pg
命令在显示器上显示
sort
命令排序后的内容。

维护变量

Shell
可以维护一些变量。变量中存放一些数据供以后使用。用户可以用
=
给变量赋值,如
:

$lookup=/usr/mydir

该命令建立一个名为
lookup
的变量并给其赋值
/usr/mydir,
以后用户可以在命令行中使用
lookup
来代替
/usr/mydir
,例如
:

$echo $lookup

结果显示
:/usr/mydir

为了使变量能被子进程使用
,
可用
exprot
命令,例如
:

$lookup=/usr/mydir

$export lookup

运行环境控制
:当用户登陆启动
shell
后,
shell
要为用户创建一个工作的环境,如下
:

1>

login
程序激活用户
shell
后,将为用户建立环境变量。从
/etc/profile

.profile
文件中读出,在这些文件中一般都用
$TERM
变量设置终端类型,用
$PATH
变量设置
Shell
寻找可执行文件的路径。

2>

/etc/passwd
文件或命令行启动
shell
时,用户可以给
shell
程序指定一些参数,例如
-x
,可以在命令执行前显示该命令及其参数。后面详细介绍这些参数。

shell
编程
:本文主要介绍的内容。

shell
本身也是一种语言
(*
可以先理解为
unix
命令的组合,加上类
C
的条件,循环等程序控制语句
,
类似
dos
批处理,但要强大的多
),
用户可以
通过
shell
编程
(
脚本
,
文本文件
)
,完成特定的工作。

SHELL
变量

下面我们详细的介绍
Bourne Shell
的编程
:

自从贝尔实验室设计了
Bourne Shell
。从那时起许多厂商根据不同的硬件平台设计了许多版本得
unix
。但在众多版本的
unix
中,
Bourne Shell
一直保持一致。

1>Bsh
的启动:用户在登陆后,系统根据文件
/etc/passwd
中有关该用户的信息项启动
Shell
。例如某用户在
passwd

的信息项为
:

ice_walk:!:411:103:Imsnow ,ice_walk:/home/ice_walk:/bin/bsh

则表明,用户名是
ice_walk
等信息,在最后一项
/bin/bsh
表明用户的
sh
环境类型是
bsh,
于是系统启动之。在启动或执行
(
包括下面我们要讲

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:

3>Bsh
的变量

前面我们在多个地方引用了变量
,

Shell
遇到一个
$
符时
(
没有被引用或逃逸
)
,它将认为其后为一变量。不论该变量是环境变量还是用户自定义的变量,在命令行中变量名要被变量值替换。例如命令
:ls $HOME
将列出变量
HOME
对应目录下的文件。
用户可以在命令行中的任何地方进行变量替换。包括命令名本身,例如:

$dir=ls

$$dir f*

将列出以
f
开头的文件。

现在详细的介绍下
Bsh
的变量。
Bsh
中有四类变量
:
用户定义的变量、位置变量
(shell
参数
)
、预定义变量及环境变量。

用户定义的变量:

用户定义的变量由字母和下划线组成,并且变量名的第一个字符不能为数字
(0~9)
。与其他
UNIX
名字一样,变量名是大小写敏感的。用户可以在命令行上用
=
给变量赋值,例如
:

$NAME=ice_walk

给变量
NAME
赋值为
ice_walk,
在应用变量
NAME
的时候,在
NAME
前加
$
即可,前面已说,不再废话
(
别说我废话多,关键是没当过老师
:()
。可以用变量和其他字符组成新的字,例如
:

$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

4>
位置变量或
Shell
参数


shell
解释用户的命令时,将把命令行的第一个字作为命令,而其他的字作为参数。当命令对应的可执行文件为
Shell
程序时,这些参数将作为位置变量传送给该程序。第一个参数记为
$1,
第二个为
$2....
第九个为
$9
。其中
1

9
是真正的参数名,
$
符只是用来标识变量的替换。

位置变量
$0
指命令对应的可执行文件名。在后面将详细介绍位置变量。

1.
只读变量

用户将变量赋值后,为了防止以后对该变量的修改,可以用以下命令将该变量设置为只读变量:

readonly variable

2.export
命令

shell
执行一个程序时,首先为该程序建立一个新的执行环境,称为子
shell
。在
Bourne Shell
中变量都是局部的,即他们只在创建他们的
Shell
中有意义。用户可以用
export
命令让变量被其他子
Shell
识别。但某用户的变量是没法让其他用户使用的。

当用户启动一个新
shell

,

shell
将使用默认的提示符。因为赋给变量
PS1
的值只在当前
shell
中有效。为了让子
Shell
使用当前
Shell
中定义的提示符号,可以使用
export
命令:

$PS1=Enter command:

Enter command:export PS1

Enter command:sh

Enter command:

此时变量
PS1
变成了全局变量。它可以被其子
Shell
使用。当变量被设置成全局的以后,将一直保持有效直到用户退出该变量所在的
Shell
。用户可以在文件
.profile
中给一个变量永久赋值。详见规范
Shell


基本语句

从本节起,我们将详细介绍
Shell
程序设计的基本知识,通过编写
Shell
脚本,用户可以根据自己的需要有条件的或者重复的执行命令。通过
Shell
程序,可以把单个的
UNIX
命令组合成一个完全实用的工具,完成用户的任务。

1>
什么是
Shell
程序

当用户在
UNIX Shell
中输入了一条复杂的命令,如
:

$ls -R /|greo myname |pg

我们可以称用户在对
Shell
编程,当把这条语句写在一个文件里,并且符给该文件可执行权限,那么该文件就是我们传统上说的
Shell
程序。

2>
简单的
Shell
程序

假设用户每天使用下述命令备份自己的数据文件
:

$cd /usr/icewalk;ls * |cpio -o > /dev/fd0

我们可以把它写在一个文件,如
:ba.sh

:

$cat >ba.sh

cd /usr/icewalk

ls * |cpio -o > /dev/fd0

^D

(ctrl_d)

程序
ba.sh
就是
Shell
脚本,用户可以用
vi
或其他编辑工具编写更复杂的脚本。

此时用户备份文件只需要执行
Shell
程序
ba.sh,
执行时需在当前
Shell
中创建一个子
Shell:

$sh ba.sh

程序
sh
与用户登陆时执行的
Bourne Shell
相同,但当
Sh
命令带参数
ba.sh
后,它将不再是一个交互式的
Shell
,而是直接从文件
ba.sh
中读取命令。

执行
ba.sh
中命令的另一方法是给文件
ba.sh
执行权限:

$chmod +x ba.sh

此时,用户可以输入文件名
ba.sh
做为一个命令来备份自己的数据,需要注意的是,用这种方法执行命令的时候,文件
ba.sh
必须存在于环境变量
$PATH
所指定的路径上
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: