目标
完成这一章,你可以做到以下事情:
※使用shell的替代功能,包括变量替代,命令替代,和波浪号替代。
※设置和修改shell变量。
※将局部变量传给环境。
※ 使变量对子进程生效。
※ 解释进程是如何被创建的。
7.0 shell 的替代功能
在shell 中有三种类型的替代:
※变量替代
※命令替代
※波浪号替代
替代的作用是加速命令行的键入和执行
7.1 Shell 变量存储
Shell内有两块内存区域用于存储shell变量,它们是:局部数据区域和环境。当定义了一个新的变量时,内存会被分配给局部数据区域,在这个区域中的变量是当前shell
私有的,通常称为局部变量,任何以后的子进程都不会存取到这些局部变量。但是,子进程能够存取那些传送到环境中去的变量。
在你的登录进程过程中,有几个特殊的shell变量会被定义。其中大多数的变量存储在环境中:一些变量,例如 ps1
和ps2,存储在局部数据区域。这些变量的值能够被改变,用于定制你的终端特性。
env 命令能够显示当前保存在环境中所有的变量,例如:
$ env
MANPATH=/usr/share/man: /usr/contrib/man: /usr/local/man
PATH=/usr/bin: /usr/ccs/bin:/usr/contrib/bin: /usr/local/bin
LOGNAME=user3
ERASE=^H
SHELL=/usr/bin/sh
HOME=/home/user3
TERM=hpterm
PWD=/home/user3
TZ=PST8PDT
EDTOR=/usr/bin/vi
7.2 设置Shell变量
语法: name=value
例子:
$color=lavender ?? ? ?????? 给一个局部变量赋值
$count=3 ?????????????? 给一个局部变量赋值
$dir_name=tree/car.models/ford ?? 给一个局部变量赋值
$PS1=hi_there?????????? ? 更改环境变量的值
$set ??????????? ?????显示所有的变量和值
当一个用户创建了一个新的变量,例如 color ,这个变量会存储在局部数据区域中。当给一个已经存在的环境变量赋予一个新值,例如 path
,这个新值会代替环境中的旧的值。
7.3 变量替代
1.语法:
$name ?????执行一个变量替代
例子:
$ echo $PATH
/usr/bin:/usr/contrib/bin:/usr/local/bin:/home/user3:.
$ echo $HOME
/home/user3
$file_name=$HOME/file1
$more $file_name
每一个变量都有一个关联值。当使用“$变量名”来对这个变量进行引用时 ,shell
会用变量的值来代替这个参数。这个过程被称为变量替代,这是shell在执行输入的命令前执行的任务之一。在shell
完成了所有的命令行的变量替代后,就会开始执行这个命令。因此,变量可以代替命令,命令参数,或者一条完整的命令行。这提供了一种机制来方便用户重命名哪些经常使用的长的路径名,或长的命令字符串。
例子:
上例示范了一些shell变量的用法。请注意,变量替代能够出现在命令行的任何位置,在一个命令行中可以有多个变量。如上例所示,一个已经存在的变量的值能够用来更新当前变量的值。
$ echo $PATH
/usr/bin:/usr/contrib/bin:/usr/local/bin
$ PATH=$PATH:$HOME:.
$echo $ PATH
/usr/bin:/usr/contrib/bin:/usr/local/bin:/home/user3:.
$ echo $HOME
/home/user3
$ file_name=$HOME/file1 file_name=/home/user3/file1
$ more $file_name more /home/user3/file1
echo $name 命令是最常用的方式用于显示变量当前的值。
{} 的用法
确认你有一个叫file和一个叫file1的变量。能够使用以下的语句给它们赋值:
$ file =this
$ file1= that
$echo $fileand$file1 寻找变量fileand,file1
sh: fileand: parameter not set
$ echo ${file} and $file1 寻找变量file,file1
thisandthat
2.花括号被用来区分变量名和周围的文本。
7.4 变量替代(2)
$dir_name=tree/car.models/ford
$echo $dir_name
tree/car.models/ford
$ls –F $dir_name
sedan/ sports/
$ my_ls =”ls –aFC”
$ $my_ls
./ file.1 tree/
../ file.2
$ $my_ls $dir_name
./ ../ sedan/ sports/
$ cd /tmp
$ dir_name=/home/user2/tree/dog.breeds/retriever
$ $my_ls $dir_name
./ ../ golden labrador mixed
在指定一个文件或目录时,使用一个绝对路径作为一个变量的值。会让你在文件系统的任何位置都可以存取你想要的文件或目录。
上例的解释:
$dir_name= tree/car.models/ford
$ echo $dir_name echo tree/car.models/ford
tree/car.models/ford
$ ls –F $dir_name ls –F tree/car.models/ford
swdan/ sports/
$ my_ls = “ls –aFC” 使用引号让shell 忽略空格
$ $my_ls ls -aFC
./ file.1 tree/
../ file.2
$my_ls $dir_name ls –aFC tree/car.models/ford
./ ../ sedan/ sports/
$ cd /tmp
$ dir_name=/home/user2/tree/dog.breeds/retriever
$ $my_ls $dir_name ls –aFC /home/user2/tree/dog,breeds/retriever
./ ../ golden labrador mixed
7.5 命令替代
语法:
$(command)
例子:
$pwd
/home/user2
$ curdir=$(pwd)
$ echo $curdir
/home/user2
$ cd /tmp
$ pwd
$ cd $curdir
$ pwd
/home/user2
命令替代用来替代一个命令和命令行输出。命令替代的标准语法,也是POSIX鼓励的一种语法是:$(command).
命令替代让你捕获一个命令的输出,用它作为另一个命令的参数,或是赋值给一个变量。象在变量替代中的一样,命令替代的执行是在命令行开始之前完成的。当命令行输出包含回车换行,它们会被空格代替。
同变量替代相似,命令替代使用一个美元符号之后的用括号包围的一个命令。 所有有效的shell脚本都可以加入命令替代。Shell
扫描每行脚本,执行它发现的开始于一个开括号,结束与于一个闭括号的命令。
命令替代的另外一种格式是用单引号来环绕一个命令象:
‘command’
它和$(command) 是等价的,并且这是Bourne
Shell认证的唯一的形式。’command’形式可以用在POSIX的脚本中和Bourne Shell的脚本中。
命令替代通常是在将一个命令的输出赋给一个变量或以后的处理时使用。通常pwd命令将它的输出送到你的屏幕。当你执行以下的赋值语句:
$ curdir=$(pwd) 或 $ curdir=’pwd’
pwd 的输出被赋给变量 curdir。
7.6 波浪号替代
$ echo $HOME
/home/user3
$ echo ~
/home/user3
$ cd tree
$ echo $PWD
/home/user3/tree
$ ls ~+ /dog.breeds
collie poodle
$ehco $OLDPWD
/home/user3/mail
$ ls ~-
/home/user3/mail/from.mike /home/user3/mail/form.jim
$echo ~tricia/file1
/home/tricia/file1
如果一个单词以一个波浪符(~)开头,这个单词被执行一个波浪符扩充,注意波浪符扩充只在一个单词的开始才会起作用,这个意思是:/~home/user3
没有波浪号扩充的功能,波浪扩充有以下的规则:
单个地波浪号或是在/ 之前代表HOME变量中设置的路径名。
一个波浪号跟一个+号代表PWD变量的值。PWD的值是在cd 到一个新的,当前的,工作目录时被设定的。
一个波浪号跟一个-号会代表OLDPWD变量的值。OLDPWD变量是在cd 前一个工作目录时被设定的。
如果一个波浪号跟一个字符串,然后是一个/ 符号 ,shell
会检查字符串是否与用户在系统中的名字一致。如果一致,~字符串会被用户登录的路径名所代替。
波浪符号也能在别名中引用:
$pwd
/home/user3
$alias cdn=’cd ~/bin’
$ cdn
$pwd
/home/user3/bin
7.7 显示变量的值 $ echo $HOME
/home/user3
$env
HOME=/home/user3
PATH=/usr/bin:/usr/contrib/bin:/usr/local/bin
SHELL=/usr/bin/sh
$ set
HOME=/home/user3
PATH=/usr/bin:/usr/contrib/bin:/usr/local/bin
SHELL=/usr/bin/sh
dolor=lavender
dir_name=/home/user3/tree
$ unset dir_name
变量替代,($变量),可以被用来显示一个独立变量的值,无论这个变量是在本地数据区域或是在环境中。
env 命令用来显示所有的当前环境中的定义的变量,和它们的值。
set 命令会显示所有的当前定义的变量,本地和环境中的变量,和它们的值。 unset 命令用来删除指定变量的当前的值。这个指被赋为空值
NULL。
set 和unset 都是shell内建的命令,而env 是UNIX命令 /usr/bin/env.
7.8 传送局部变量到环境
语法:
export 变量 传递变量到环境
传送变量 color和 count 到环境的过程,执行了以下的命令:
$ color=lavender
$ export color
$ export count=3
$ export
export PATH=/usr/bin:/usr/ccs/bin:/usr/contrib/bin:/usr/local/bin
export color=lavender
export count=3
为了使其它的进程也能使用一个变量,这个变量必须在环境中存在。当一个变量被定义,这个变量存储在局部数据空间,必须被export
到环境中去。
exprot 命令将指定的变量从局部数据空间传递到环境数据空间,export 变量=值
会对变量进行赋值(也可能是更新),同时将这个变量放到环境中去。如果不带参数,export
命令同env命令一样会显示所有exported(输出的),变量的名字和值,注意 export 是一个shell内部的命令。
7.9 传递变量给一个应用
系统中的每一个应用或命令都会有一个相关联的存储在磁盘上的程序文件。大多数的UNIX系统命令在目录/usr/bin
下面。当执行一个命令的时候,命令相关的程序文件必须被定位,再将代码装载入内存然后执行。在UNIX系统中一个运行中的程序被称为进程。
当你登录进入一个UNIX系统时,shell 程序会被装载,一个shell
进程会被执行。当你在shell提示符下输入一个应用的(或命令)的名字后,一个子进程会被创建和执行:其过程如下:
一个fork(分叉)会复制你的shell进程,包括程序代码,环境数据空间,和局部数据空间。
一个exec 会使用子进程的代码和本地数据空间来替代原进程的本地数据空间。
exec 会在执行要求的应用进程后结束。
当子进程在执行的时候,shell
(父进程)会进入睡眠状态,等待子进程结束。一旦子进程结束执行,它会中止,释放自己使用的内存,并且唤醒父进程,父进程又可以准备接受另外的命令请求,当shell
提示符返回到屏幕上,你就知道子进程已经结束。
局部变量 和 环境变量
无论何时定义一个新的变量,它都会存储在于与本进程相联系的局部数据空间中。如果一个子进程想要存取这个变量,这个变量必须被传送到环境中(使用export),一旦一个变量在环境中,它对每个后来的子进程都会有效,,因为环境变量对每个子进程都有效。
在上图中,在vi 命令之前,color 变量在shell的局部数据空间里,TERM 变量在环境里。当vi
命令执行时,shell执行一次fork
和exec;子进程的局部数据空间比子进程的程序代码所覆盖,但环境被完整地传递给子进程。因此,子进程 vi 不能存取变量
color,但是它可以存取变量TERM。Vi
编辑器需要知道用户的终端类型,用来适当地格式化它的输出。它通过读取环境变量TERM的值来获得这些信息。
唯一的传递数据给(子)进程的方法是通过环境。
7.10 监视进程状态
$ ps –f
UID PID PPID C STIME TTY TIME COMMNAD
user3 4702 1 1 08:46:40 ttyp4 0:00 -sh
user3 4895 4702 18 09:55:10 ttyp4 0:00 ps -f
$ ksh
$ ps –f
UID PID PPID C STIME TTY TIME COMMAND
user3 4702 1 0 08:46:40 ttyp4 0:00 -sh
user3 4896 4702 1 09:57:20 ttyp4 0:00 ksh
user3 4898 4896 18 09:57:26 ttyp4 0:00 ps –f
$exec ps –f
UID PID PPID C STIME TTY TIME COMMAND
user3 4702 1 0 08:46:40 ttyp4 0:00 -sh
user3 4896 4702 18 09:57:26 ttyp4 0:00 ps –f
$
系统中的每一个进程在启动的时候都被赋予一个唯一的号码,这个号码被称为进程ID(PID)。Ps
命令显示当前在你系统中运行(或睡眠)的进程的信息,包括每个进程的PID,每个进程父进程的PID(PPID)。通过PID
和PPID,你能够追踪你系统中任何进程的体系。Ps命令同时也会报告每一个进程的属主,终端号,和其他的有用的信息。
ps 命令通常不带参数使用,结果是给出一个与你当前终端对话相关的进程的一个简单的报表,例如:
$ ps
PID TTY TIME COMMAND
ttyp4 0:00 sh
ttyp4 0:00 ps
正如你看到的那样,这个命令显示只有shell, sh,和 ps 命令正在运行。注意两个进程的PID号码。当使用-f 选项时候,ps
命令给出一个全列表,包括PPID号,我们可以看到ps –f
命令是作为shell的一个子进程,因为它的PPID号同shell的PID号是一致的。
请记住shell 同其他的UNIX命令一样都是一个程序。如果你在当前的POSIX shell 的提示符下使用ksh 命令,一个fork
和exec会执行,一个Korn shell的子进程回北创建,并开始执行。当我们执行另一个 ps –f 的时候,我们可以发现,ksh
作为原shell,sh 的一个子进程运行,新的ps 命令作为Korn shell的一个子进程。
exec命令是一个shell内建的命令。如果用我们用 exec ps –f 来代替ps –f ,ps
的程序代码会覆盖当前的进程(ksh)的程序代码。很明显,这是因为ps –f 的PID号与ksh 使用的PID是一致的。当ps –f
结束后,我们会发现回到了最初的POSIX shell 提示符。
7.11 子进程和环境
$ export color=lavender
$ ksh (创建一个子shell进程)
$ ps -f
UID PID PPID C STIME TTY TIME COMMAND
user3 4702 1 0 08:46:40 ttyp4 0:00 -sh
user3 4896 4702 1 09:57:20 ttyp4 0:00 ksh
user3 4898 4896 18 09:57:26 ttyp4 0:00 ps –f
$ echo $color
lavender
$ color=red
$ echo $color
red
$ exit (退出子shell)
$ ps –f (回到父shell)
UID PID PPID C STIME TTY TIME COMMAND
user3 4702 1 0 08:46:40 ttyp4 0:00 -sh
user3 4895 4702 1 09:58:20 ttyp4 0:00 ps –f
$echo $color
lavender
上例说明了子进程不能够更改它们的父进程的环境。
$ ps –f
UID FSID PID PPID C STIME TTY TIME COMMAND
user3 default_system 4702 1 0 08:46:40 ttyp4 0;00 -sh
user3 default_system 4895 4702 1 09:58:20 ttyp4 0:00 ps –f
如果最初执行一个ps –f 命令,它会显示只有你的登录shell(当然还有ps )在运行。如上表中,我们给一个变量color
赋值lavender,然后将这个变量传递到环境。下一步,我们执行一个子进程。执行一个ksh命令,创建一个子Korn
shell进程。当然父进程的环境已经传递给这个子Korn
shell进程,我们可以观察到变量color的值是lavender。我们然后更改变量color的值为red。echo命令确认在子shell的环境中变量color的值已经被改变。当我们退出子shell回到父shell,我们发现富进程的环境并没有被子进程改变,变量color仍然保持原来的值lavender.
阅读(948) | 评论(0) | 转发(0) |