Lyon

个人博客

授人以鱼,亦授人以渔.


Linux Shell编程笔记 第三部分 登录环境

第三部分 登录环境

第13章 登录环境

登录系统时,在进入命令提示符前,系统要做两个工作。键入用户名和密码后,系统检查是否为有效用户,为此需查询/etc/passwd文件。如果登录名正确并且密码有效,开始下一步过程,即登录环境。在进行下一步处理之前,先看看文件/etc/passwd。这是一个文本文件,可以任意修改其中的文本域,但要小心。此文本有7个域,并用冒号作分隔符,以下是其部分文件内容列表。在顶端加有列号,这样各域标识得更加清晰。

第1域是登录名,第2域是加密的密码,第5域是用户全名。第6域是用户根目录,第7域是用户使用的shell。这里/bin/sh意即缺省为常规 Bourne Shell。

Passwd文件可能还有其他格式。其中的一个版本即为实际 passwd域保存在另一个文件中。以上即为最普通格式。 登录成功后,系统执行两个环境设置文件,第一个是 /etc/profile,第二个是.profile,位 于用户根目录下。 系统还会处理其他的初始化文件。这里只涉及profile文件。

13.1 /etc/profile

用户登录时,自动读取/etc目录下profile文件,此文件包含:

全局或局部环境变量。
PATH信息。
终端设置。
安全命令。
日期信息或放弃操作信息。

下面就来详细解释上述各项内容。设置全局环境变量便于用户及其进程和应用访问它。

PATH定位包含可执行文件,库文件及一般文本文件的目录位置,便于用户快速访问。

终端设置使系统获知用户终端的一般特性。安全命令包括文件创建模式或敏感区域的双登录提示。日期信息是一个文本文件,保存用户登录时即将发生事件的记录或放弃登录的信息文件。

13.2 用户的$HOME.profile

/etc/profile文件执行时,用户将被放入到自己的$HOME目录中,回过头来观察passwd文件,用户的$HOME目录在倒数第2列。可以将之看作用户根目录,因为正是在这里存储了所有的私有信息。

如果.profile已经存在,系统将参照此文件,意即对此过程并不创建另一个shell,因而在/etc/profile下设置的环境不做改动,除非在.profile中强制改动它。如果创建另一个进程,用户本地的shell变量将被覆盖。

回到.profile,一般来说创建帐户时,一个profile文件的基本框架即随之创建。不要忘了在.profile文件中可以通过设置相关条目以不同的值或使用uset命令来覆盖/etc/profile文件中的 设置。如果愿意,可以定制用户自己的.profile文件。

13.3 stty用法

stty用于设置终端特性。要查询现在的 stty选项,使用:

stty -a

13.4 创建.logout文件

使用Bourne shell与其他shell不同,其缺点是不包含.logout文件。此文件保存有执行exit命令时,在进程终止前执行的命令。但是通过使用trap命令,Bourneshell也可以创建自己的.logout文件。方法如下:编辑.profile文件,在最后一行加入下列命令,然后保存并退出。

trap "$HOME /.logout"0 

再键入一个.logout文件,敲入下列执行命令。如果愿意,可以在此脚本中加入任何命令。

用户退出时,调用.logout文件。过程如下:用户退出一个 shell时,传送了一个信号0,意即从现在shell中退出,在控制返回 shell继续退出命令前,.profile文件中trap行将捕获此信号并执行.logout。

第14章 环境和shell变量

为使shell编程更有效,系统提供了一些shell变量。shell变量可以保存诸如路径名、文件名或者一个数字这样的变量名。shell将其中任何设置都看做文本字符串。

有两种变量,本地和环境。严格地说可以有4种,但其余两种是只读的,可以认为是特殊变量,它用于向shell脚本传递参数。

shell变量
环境变量
变量替换
导出变量
特定变量

14.1 什么是shell变量

变量可以定制用户本身的工作环境。使用变量可以保存有用信息,使系统获知用户相关设置。变量也用于保存暂时信息。

例如:一变量为 EDITOR,系统中有许多编辑工具,但哪一 个适用于系统呢?将此编辑器名称赋给 EDITOR,这样,在使用 cron或其他需要编辑器的应用时,这就是你将一直使用的 EDITOR取值,并将之用作缺省编辑器。

下面是一个例子,登录的审核系统需要编辑。在菜单中选择此选项时,应用查询EDITOR变量值,其值为vi。系统知道可使用此编辑器。另一个例子需要登录数据库系统,键入下列命令:

$ isql -U lyon -P abcd -S lyonserver 

这里-S为正在连接的服务器名称。有一变量DSQUERY保存服务器名称值。设置服务器名称值到 DSQUERY变量,这样如果登录时不使用 -S提供服务器名称,应用将查询DSQUERY变量,并使用其取值作为服务器名称。需要做的全部工作就是键入下列命令:

$ isql -U lyon -P abcd 

工作方式同上例。

14.2 本地变量

本地变量在用户现在的shell

生命期的脚本中使用。例如,本地变量file-name取值为 loop.doc,这个值只在用户当前shell生命期有意义。如果在shell中启动另一个进程或退出,此值将无效。这个方法的优点就是用户不能对其他的shell或进程设置此变量有效。

表14-1列出各种实际变量模式 使用变量时,如果用花括号将之括起来,可以防止shell误解变量值,尽管不必一定要这样做,但这确实可用。要设置一本地变量,格式为:

$ variable-name=val u或e ${variable-name=value}

注意,等号两边可以有空格。如果取值包含空格,必须用双引号括起来。shell变量可以用大小写字母。

表14-1 变量设置时的不同模式

Variable-name=value 设置实际值到 variable-name Variable-name+value 如果设置了 variable-name,则重设其值 Variable-name:?value 如果未设置 variable-name,显示未定义用户错误信息 Variable-name?value 如果未设置 variable-name,显示系统错误信息 Variable-name:=value 如果未设置 variable-name,设置其值 Variable-name:-value 同上,但是取值并不设置到 variable-name,可以被替换

14.2.1 显示变量

使用echo命令可以显示单个变量取值,并在变量名前加$,可以结合使用变量,将错误信息和环境变量LOGNAME设置到变量error-msg。

14.2.2 清除变量

使用unset命令清除变量。

 unset variable-name 

14.2.3 显示所有本地shell变量

使用set命令显示所有本地定义的shell变量。set输出可能很长。查看输出时可以看出shell已经设置了一些用户变量以使工作环境更加容易使用。

14.2.4 结合变量值

将变量并排可以使变量结合在一起:

14.2.5 测试变量是否已经设置

有时要测试是否已设置或初始化变量。如果未设置或初始化,就可以使用另一值。此命令格式为:

${variable:-value}

意即如果设置了变量值,则使用它,如果未设置,则取新值。

14.2.6 使用变量来保存系统命令参数

可以用变量保存系统命令参数的替换信息。下面的例子使用变量保存文件拷贝的文件名信息。变量source保存passwd文件的路径, dest保存cp命令中文件目标。

$ SOURCE="/etc/passwd"
$ DEST=“/tmp/paswd.bak”
$ cp ${SOURCE}${DEST}

14.2.7 设置只读变量

如果设置变量时,不想再改变其值,可以将之设置为只读方式。如果有人包括用户本人 想要改变它,则返回错误信息。格式如下:

variable-name=value 
readonly variable-name 

要查看所有只读变量,使用命令readonly即可。

14.3 环境变量

环境变量用于所有用户进程(经常称为子进程)。登录进程称为父进程。

shell中执行的用户进程均称为子进程。不像本地变量(只用于现在的shell)环境变量可用于所有子进程,这包括编辑器、脚本和应用。

环境变量可以在命令行中设置,但用户注销时这些值将丢失,因此最好在 .profile文件中定义。系统管理员可能在/etc/profile文件中已经设置了一些环境变量。将之放入profile文件意味着每次登录时这些值都将被初始化。

传统上,所有环境变量均为大写。环境变量应用于用户进程前,必须用export命令导出。 环境变量与本地变量设置方式相同。

14.3.1 设置环境变量

VARIABLE-NAME=value;export VARIABLE-NAME 

在两个命令之间是一个分号,也可以这样写:

VARIABLE-NAME=value Export VARIABLE-NAME 

14.3.2 显示环境变量

使用env命令可以查看所有的环境变量。

14.3.3 清除环境变量

使用unset命令清除环境变量:

14.3.4 嵌入shell变量

Brourneshell有一些预留的环境变量名,这些变量名不能用作其他用途。通常在/etc/profile中建立这些嵌入的环境变量,但也不完全是,这取决于用户自己。以下是嵌入shell变量列表。

1.CDPATH

改变目录路径变量,保留一系列由冒号隔开的路径名,用于 cd命令。如果设置了CDPATH,cd一个目录时,首先查找CDPATH,如果CDPATH指明此目录,则此目录成为当前工作目录。例子如下:

$ CDPATH=:/home/dave/bin:/usr/loca l ;/export CDPATH. 

如果要

$ cd apps cd命令首先在 CDPATH中查找目录列表,如果发现apps,则它成为当前工作目录。

2.EXINIT

EXINIT变量保存使用vi编辑器时的初始化选项。例如,调用 vi时,要显示行号,且在第10个空格加入tab键,命令为: $ EXINIT=’set nutab=10’;export EXINIT

3.HOME

HOME目录,通常定位于passwd文件的倒数第2列,用于保存用户自身文件。设置了HOME目录,可以简单使用cd命令进入它cd $HOME

4.IFS

IFS用作shell指定的缺省域分隔符。原理上讲域分隔符可以是任意字符,但缺省通常为空格、新行或tab键。IFS在分隔文件或变量中各域时很有用。下面的例子将 IFS设置为冒号,然后echo PATH变量,给出一个目录分隔开来的可读性很强的路径列表。

5.LOGNAME

此变量保存登录名,应该为缺省设置,但如果没有设置,可使用下面命令完成它:

6.MAIL

MAIL变量保存邮箱路径名,缺省为 /var/spool/mail/。shell周期性检查新邮件,如果有了新邮件,在命令行会出现一个提示信息。如果邮箱并不在以上指定位置,可以用MAIL设置。

$ MAIL=/usr/mail/lyon;export MAIL 

7.MAILCHECK

MAILCHECK缺省每60s检查新邮件,但如果不想如此频繁检查新邮件,比如设为每2m,使用命令:

$ MAILCHECK=1 2;0export MAILCHECK 

8.MAILPATH

如果有多个邮箱要用到MAILPATH,此变量设置将覆盖MAIL设置。

$ MAILPATH=/var/spool/lyon:/var/spool /;exmport MAILPATH 

上面的例子中, MAIL检测邮箱lyon和admin。

9.PATH

PATH变量保存进行命令或脚本查找的目录顺序,正确排列这个次序很重要,可以在执行命令时节省时间。你一定不想在已知命令不存在的目录下去查找它。

通常情况,最好首先放在HOME目录下,接下来是从最常用到一般使用到不常用的目录列表次序。如果要在当前工作目录下查询,无论在哪儿,均可以使用句点操作。目录间用冒号分隔,例如:

$ PATH=$HOME/bin:.:/bin:/usr;/ export PATH 

使用上面的例子首先查找 HOME/bin目录,然后是当前工作目录,然后是/bin,最后是 /usr/bin。 PATH可以在系统目录下 /etc/profile中设置,也可以使用下面方法加入自己的查找目录。

$ PATH=$PATH:/$HOME/bin: .export PATH 

这里使用了/etc/profile中定义的PATH,并加入$HOME/bin和当前工作目录。一般来说,在查找路径开始使用当前工作目录不是一个好办法,这样很容易被其他用户发现。

10.PS1

基本提示符包含 shell提示符,缺省对超级用户为#,其他为 $。可以使用任何符号作提示符

11.PS2

PS2为附属提示符,缺省为符号>。PS2用于执行多行命令或超过一行的一个命令。

12.SHELL

SHELL变量保存缺省shell,通常在/etc/passwd中已设置,但是如有必要使用另一个shell,可以用如下方法覆盖当前shell:

13.TERMINFO

终端初始化变量保存终端配置文件的位置。通常在/usr/lib/terminfo或/usr/share/terminfo

$ TERMINFO=/usr/lib/terminfo;export TERMINFO 

14.TERM

TERM变量保存终端类型。设置TERM使应用获知终端对屏幕和键盘响应的控制序列类型, 常用的有 vt100、vt200、vt220-8等。 $ TERM=vt1 0;0 export TERM

15.TZ

时区变量保存时区值,只有系统管理员才可以更改此设置。例如:

$ echo $TZ

返回值表明正在使用格林威治标准时间,与GMT时差为0,并作EDT保存。

14.3.5 其他环境变量

还有一些预留的环境变量。其他系统或命令行应用将用到它们。以下是最常用的一些, 注意这些值均未有缺省设置,必须显示说明。

1.EDITOR

设置编辑器,最常用。

$ EDITOR= v;i export EDITOR 

2.PWD

当前目录路径名,用 cd命令设置此选项。

3.PAGER

保存屏幕翻页命令,如 pg、more,在查看 man文本时用到此功能。

$ PAGER='pg -f -p %;d 'export PAGER 

4.MANPATH

保存系统上man文本的目录。目录间用冒号分隔。

$ MANPATH=/usr/apps/man:/usr/loca l;/emxapnort MANPATH 

5.LPDEST或PRINTER

保存缺省打印机名,用于打印作业时指定打印机名。

$ LPDEST=hp3si-systems 

14.3.6 set命令

$HOME.profile文件中设置环境变量时,还有另一种方法导出这些变量。使用set命令-a选项,即set-a指明所有变量直接被导出。不要在/etc/profile中使用这种方法,最好只在自己的$HOME.profile文件中使用。

14.3.7 将变量导出到子进程

shell新用户碰到的问题之一是定义的变量如何导出到子进程。前面已经讨论过环境变量的工作方式,现在用脚本实现它,并在脚本中调用另一脚本(这实际上创建了一个子进程)。

以下是两个脚本列表father和child。father脚本设置变量 film,取值为A Few Good Men,并将变量信息返回屏幕,然后调用脚本child,这段脚本显示第一个脚本里的变量film,然后改变其值为DieHard,再将其显示在屏幕上,最后控制返回father脚本,再次显示这个变量。 在father脚本中加入export命令,以便child脚本知道 film变量的取值,这就会工作:因为在脚本中加入了export命令,因此可以在任意多的脚本中使用变量film,它们均继承 了film的所有权。

不可以将变量从子进程导出到文进程,然面通过重定向就可做到这一点

14.4 位置变量参数

本章开始提到有4种变量,本地、环境,还有两种变量被认为是特殊变量,因为它们是只读的。这两种变量即为位置变量和特定变量参数。先来看一看位置变量。

如果要向一个shell脚本传递信息,可以使用位置参数完成此功能。参数相关数目传入脚本,此数目可以任意多,但只有前9个可以被访问,使用shift命令可以改变这个限制。本书后面将讲到 shift命令。参数从第一个开始,在第9个结束;每个访问参数前要加$符号。第一个参数为0,表示预留保存实际脚本名字。无论脚本是否有参数,此值均可用。

14.4.1 在脚本中使用位置参数

注意$0返回当前目录路径,如果只返回脚本名,在basename命令下参数设为$0,刚好得到脚本名字。

14.4.2 向系统命令传递参数

可以在脚本中向系统命令传递参数

14.4.3 特定变量参数

既然已经知道了如何访问和使用shell脚本中的参数,多知道一点相关信息也是很有用的,有必要知道脚本运行时的一些相关控制信息,这就是特定变量的由来。共有7个特定变量, 见 表14-2。

表14-2

特定shell 变量
$# 传递到脚本的参数个数
$* 以一个单字符串显示所有向脚本传递的参数。与位置变量同,此选项参数可超过 9个
$$ 脚本运行的当前进程ID号
$! 后台运行的最后一个进程的进程ID号
$@ 与$#相同,但是使用时加引号,并在引号中返回每个参数
$- 显示shell使用的当前选项,与set命令功能相同
$? 显示最后命令的退出状态
0 表示没有错误,其他任何值表明有错误

14.4.4 最后的退出状态

注意,$?返回0。可以在任何命令或脚本中返回此变量以获得返回信息。 基于此信息,可 以在脚本中做更进一步的研究,返回 0意味着成功,1为出现错误。

第15章 引号

上一章介绍了变量和替换操作,在脚本中执行变量替换时最容易犯的一个错误就是由于 引用错误。在命令行中引用是很重要的。

15.1 引用必要性

这里只讲述引用的基本规则。因为使用引用的例子很多。本书接下来的两个部分将一一予以讲述。脚本中执行行操作时,shell将对脚本设置予以解释。要采取一种方法防止shell这样做,即使用引用号,包括各式引用或使用反斜线。一些用户在对文本字符串进行反馈操作时觉得使用引用很麻烦。有时不注意,只引用了 一半,这时问题出现了。最好在反馈文本字符串时使用双引号。

表15-1

shell 引用类型 shell 引用类型
”” 双引号 反引号
’’ 单引号 \ 反斜线

15.2 双引号

使用双引号可引用除字符$、`、\外的任意字符或字符串。这些特殊字符分别为美元符号,反引号和反斜线,对shell来说,它们有特殊意义。如果使用双引号将字符串赋给变量并反馈它,实际上与直接反馈变量并无差别。

15.3 单引号

单引号与双引号类似,不同的是shell会忽略任何引用值。换句话说,如果屏蔽了其特殊含义,会将引号里的所有字符,包括引号都作为一个字符串。

15.4 反引号

反引号用于设置系统命令的输出到变量。shell将反引号中的内容作为一个系统命令,并执行其内容。使用这种方法可以替换输出为一个变量。反引号可以与引号结合使用。

15.5 反斜线

如果下一个字符有特殊含义,反斜线防止shell误解其含义,即屏蔽其特殊含义。 下述字 符包含有特殊意义:

& * + ^ $ ` " | ?

假定echo命令加*,意即以串行顺序打印当前整个目录列表,而不是一个星号 *

在打印字符串时要加入八进制字符(ASCII相应字符),必须在前面加反斜线,否则shell将其当作普通数字处理。 $$命令, shell解释其为现在进程ID号,使用反斜线屏蔽此意,仅打印$$使用命令expr时,用表示乘法会出现错误,在前加上反斜线才会正确。在echo命令中加入元字符,必须用反斜线起屏蔽作用 显示价格 $19.99。其中$屏蔽与不屏蔽将产生不同的结果。

1) 反馈字符串用双引号;但不要引用反馈本身。
2) 如果使用引用得到的结果不理想,再试另一种,毕竟只有三种引用方式,可以充分尝试。