2006年11月27日星期一

1.6. 文件

1.6. 文件

尽管命令的参数不总是文件,但是文件确实UNIX系统中最重要一类型的 “东西”。文件可以包含各种信息,实际上有各种不同类型的文件。从根本上来说最主要有三个类型:

正规文件

同时又称为文本文件;这里面包含可读的字符。举例来说,这本书是几个由人类可以查看的格式及可读的字符正规文件组成。

可运行文件

同时成为程序;这里面包含着命令。有些人们不能直接阅读;还有些—shell脚本(shell scripts)则由特殊的文本组成的文件,这也是我们这本书我们将要介绍的。Shell本身是一个叫做bash的可运行文件(不能直接阅读)。

目录

在其它文件格式里称为文件夹和子目录。These are like folders that contain other files—possibly other directories (called subdirectories).

1.6.1. 目录

让我们回顾下目录最重要的概念。实际上在UNIX系统中所有的文件目录可以按照等级形式包含其它目录,也就是大家所说的树形架构。

Figure 1-2 表现的是目录树的典型,直角长方形代表目录,圆角类方形则代表正规文件。

Figure 1-2. 目录文件的树形架构


在这棵树的顶端的目录称为系统的根目录(但未命名)[6] 。所有文件以他们的位置和根目录相递归的关系命名;这样的命名是以斜杠(/)分隔所有目录的层次列表(相对于根)最后跟随文件名称。 这种方法命名的文件称作全路径名称(或绝对目录)。

[6] 大部分UNIX指南命名根目录为/。我们倾向于选择未命名,因为这样从逻辑符合UNIX文件名命名规则。

举例,说在根目录下home里有目录cam,cam下有book目录有个文件叫aaix。这个文件的全路径命名是/home/cam/book/aaiw。

1.6.1.1 工作目录

当然,使用完全路径命名访问你所需要的指定的文件并不令人舒服。所以有种概念叫做工作目录(有时也称当前目录),指的是你输入任何东西时你所在的目录。若是你输入的路径名称前没有斜杠,那么位置是相对于工作目录的。这种路径名称称为相对路径;你使用它会比使用全路径更加频繁。

当你登录到系统,你的工作目录是初始设置的一个特殊目录叫做你的主(或登录)目录。系统管理员常常使系统将每个人的home目录名设置为和他们的登录名相同,所有的主目录都包含在根目录以下。

举例来说,/home/cam是典型的主目录。若是你现在工作在此目录下并输入命令lp memo,系统会在/home/cam目录中查找memo文件。若是你有一个目录在你的主目录下,它又包含一个文件teatime,你若是要打印它的话使用命令lp hatter/teatime。

1.6.1.2 ~(Tilde)符号

正如你所预料的,主目录经常出现砸目录中。虽然许多系统组织所有的主目录有一个共同的上一级目录(譬如/home或/users),你亦不愿依赖此方法或使用你所知的绝对路径访问某人的主目录。

因此bash拥有简写的方式访问主目录:在用户名前添加一个波浪号~。譬如,你要查阅用户alice的主目录里的story文件是~alice/story。这是一个绝对路径名,所以使用时不用担心你的工作目录。若是此文件在alice主目录有一个子目录adventure中,你可以使用~alice/adventurestory访问。

还有更方便的,一个波浪号代表你自己的主目录。你可以使用~/notes指定在你主目录的notes文件(注意它和~notes的差别,shell会解析~notes指向一个用户叫notes的主目录)。若是notes在你adventure子目录中,你可以用~/adventure/notes。这个符号在你不在主目录时(譬如:在系统目录/tmp)很方便的切换你的工作目录到你的主目录中。

1.6.1.3 修改工作路径

若是你想更改你的工作目录,使用命令cd。若是你不记得你的工作目录,命令pwd会告诉你。

cd携带一个你想成为你工作目录的目录名作为参数。它可以转移当前目录,也可以包含波浪号,或者可以使绝对路径(以斜杠开始)。若是你忽略了参数,cd切换到你的主目录(例,她和cd ~一样)。

Table 1-1 给出了一些cd命令的例子。每个命令假设你运行命令前你的工作目录是/home/cam,你的目录架构如Figure 1-1。

Table 1-1. Sample cd commands

命令

新的工作目录

cd book

/home/cam/book

cd book/wonderland

/home/cam/book/wonderland

cd ~/book/wonderland

/home/cam/book/wonderland

cd /usr/lib

/usr/lib

cd ..

/home

cd ../gryphon

/home/gryphon

cd ~gryphon

/home/gryphon


前四个比较易懂。剩下的两个使用了特殊的目录称为..(两个点),意思是“当前目录的父目录”。每一个目录都有一个,它是普遍且含路径到结构中的上一层目录—也被称为父目录。[7]

[7] 每个目录还有一个特殊的目录.(一个点),这个意思是指“当前目录”。因此,cd .不做任何实在的事。 目录的.和..实际上是特殊隐藏文件分别指向它自己和父目录。

另一个bash的cd特性是cd -,无论你现在在何目录都指向你先前所在的目录。举例,若是你开始在/usr/lib,输入无任何参数cd切换到你的主目录,再输入cd -,你会返回到/usr/lib。

1.6.2. 文件名,通配符和文件名扩展

有时你需要同时运行超过一个文件。最普通的例子是如命令ls,可以列出文件信息。最简单的形式,没有选项和参数,它会列出所有除了隐藏文件(以.开始命名的文件)外所有的文件名称。

若是你给出文件名参数,他会列出这个文件:譬如你的当前目录有文件duchess和queen,你输入ls duchess queen,系统会简单得打印出文件名。

实际上,ls经常使用选项使它可以列出文件的信息,譬如-l(long)选项,这个选项就是使ls列出文件的所有者、大小、何最后修改的时间和其他信息;或者-a(all),这个选项会列出隐藏文件。但是有时你会想验证某一类文件但是有不确切知道它的名称;譬如,若是你使用文本编辑器,你会想知道你当前目录有什么文件是以.txt结尾的。

文件名在UNIX中非常重要,shell因此提供了些内置的方法查找不确切文件名的文件。你可以使用特殊的字符(叫做通配符),它们可以在文件名中替代某一部分。Table 1-2 列出基本的通配符。

Table 1-2. 基本通配符

通配符

代替

?

任何单一字符

*

任何字符串

[set]

任何在集合中的字符

[!set]

任何不在集合中的字符


?通配符符合任何单一的字符,所以若是你的目录中包含文件program.c, program.log和program.o,则表达式program.?匹配program.c和program.o但是不匹配program.log。

星号(*)在通配符使用中功能最大;它匹配任何字符串。在上一段种表达式program.*匹配所有的文件;文本编辑器用户可以使用表达式:*.txt去符合他们的输入文件。[8]

[8] MS-DOS和VAX/VMS用户要注意的是点(.)在UNIX文件文件里没有任何特别的(除非以点开始,也就是隐藏文件,那是另外的特征)。譬如,ls *列出当前目录的所有文件,你无须像其他系统一样输入*.*。实际上*.*不会列出所有的文件,只会列出那些名称中间至少有一个点的文件。

Table 1-3 将帮助示范你如何使用*。假定你有文件bob、darlene、dave、ed、frank和fred在你的工作目录。



Table 1-3. 使用*通配符

表达式

替代

fr*

frank fred

*ed

ed fred

b*

bob

*e*

darlene dave ed fred

*r*

darlene frank fred

*

bob darlene dave ed frank fred

d*e

darlene dave

g*

g*


注意*可以代表什么都没有:*ed和*e*都符合ed。另外需要注意的是最后一个例子表示当shell不能匹配任何名称时:它将会保持通配符不被改变。

剩下的通配符是组合结构。组合可以是字符的队列(譬如,abc)和可能包含字符的排列(譬如,a-z),或者两者的结合。若是你想包含一段字符,只需要标注开始和结尾的字符。Table 1-4 将更详细的解释。

Table 1-4. Using the set construct wildcards

表达式

替代

[abc]

a, b, 或 c

[.,;]

Period, comma, or semicolon

[-_]

Dash or underscore

[a-c]

a, b, or c

[a-z]

All lowercase letters

[!0-9]

All non-digits

[0-9!]

All digits and exclamation point

[a-zA-Z]

All lower- and uppercase letters

[a-zA-Z0-9_-]

All letters, all digits, underscore, and dash


在最初的通配符例子里,program.[co]和program.[a-z]都符合program.c和program.o,但是不对应program.log。

在左括号后的感叹号用来“否定”组合。譬如,[!.;]对应除了句号和分号以外的所有字符;[!a-zA-Z]对应所有除了不是字母以外的字符。对应!自己,则需要放在组合的头一个字符后,或者在他前面放一个反斜杠,如[!]。

排列符号非常便捷,但是您最好不要设定太多的符号在排列里。排列符号可以放心的使用诸如大写字母,小写字母,数字,或者其它子排列(譬如[f-g],[2-6])。不要期望使用混合字母和标点符号:譬如,[a-Z]和[A-z]就不能认为包括所有的字母或者其它内容。原因是排列在不同种类的计算机上没有完全的统一。[9]

[9] 明确的说是,排列以您计算机使用的字符编码配置(普通为ASCII,但是IBM大型机使用EBCDIC)和字符所配置当前场所(在非英语环境里排列未必输出期望的值)所决定。

包含通配符表达式对应到文件名的过程叫通配符表达式或者globbing。读取和处理命令行只是shell几个处理中的一步;其他有诸如我们已经看见的发音符表达式(tilde expansion),也就是在应用中代替主目录(home directories)的表达式。我们将在后面的章节中看到其他的,详细的过程会在Chapter 7中列举。

不管怎样,重要的是您要了解您所运行的命令只是接受了通配符表达式的结果。这意味这,它们不能知道这些参数会变成什么。譬如,若是你输入ls fr*并且您的文件是与前几页提到的目录一样,那么shell解释出命令行为ls fred frank并且调用命令有参数fred和frank的ls命令。若是您输入ls g*,那么(由于没有匹配内容)g*会被按照文字字符串传递给ls且报出错误信息:g*:No such file or directory.[10]

[10] 在C shell的通配符机制下,这里的反映不同,C shell会报出错误信息但是根本不运行。

这里有些例子可以帮助我们理解清楚些。假设您是个C程序员。那么您一定了解后缀为.c(程序源文件),.h(程序的头文件)以及.o(不可读的目标代码)。若是您像列出您工作目录下的所有的源文件,目标文件和头文件。ls *.[cho]可以做到。Shell解释*.[cho]将所有那些后部分结尾c,h或者o的结果列表座位参数传递给ls。换句话说,ls会得到文件名称犹如他们是被一个个的输入――但是注意无论怎样我们还不知道文件的名称!我们由通配符去做到这点。

到目前为止通配符例子实际在一般概念中称为文件名扩展。(The wildcard examples that we have seen so far are actually part of a more general concept called pathname expansion.)正如在当前目录下使用通配符一样,他们同样可以用来表示文件名全称,包含全部路径。譬如,若是您像列出所有在目录/usr和/usr2目录下的文件,您可以输入ls /usr*。若是您只对这些目录下以b和e开始的文件感兴趣,您可以输入ls /usr*/[be]*去列出他们。

1.6.3. Brace Expansion(大括号表达式)

和文件名扩展的概念紧密相关的是大括号表达式。然而文件名扩展通配符扩展结果为实际存在的文件和目录,大括号表达式则为任意被给予的字符串:以一个选项的开始,存在大括号之间并跟随逗号,且以一个选项结束。若是您输入echo b{ed,olt,ar}s,您会看见如下单词:beds,bolts和bars。每个字符串实例由开始选项b和结尾选项s结合包含在大括号里字符串构成。注意这里不存在文件名――字符串无关于文件名。这里我们还可以将大括号作为容器,譬如b{ar{d,n,k},ed}s。这会解释为bards,barns,barks,beds。

您还可以一些稍微不同的大括号表达式创建连续的字母和数字。若是您输入echo {2..5}您会得到解释为2 3 4 5。输入echo {d..h}结果则是d e f g h[11]。

[11] 这个大括号表达式功能在bash Version 3.0之前不能使用。

大括号表达式中也可以使用通配符表达式。在前面提到列出源码,目标文件和头文件的例子里,我们还可以输入ls *.{c,h,o}。[12]

[12] 在C shell里此处稍微有些差异。要完成解释Bash需要至少一个逗号;否则,单词将不转换。譬如,b{o}lt意味着就是b{o}lt。

我是小偷???

上周五,一下班就立马拿起包,冲到电梯口然后就是小跑着跑到78路车站。对于公司我现在是一时也不想多呆。但是后来发生的事让我后悔这么早出来......
周五回家的人估计都像我我这么积极,公车是越挤越满,到最后我要下车时,连下车的后门都挤的下不去了,一路“借过”,“谢谢”,“麻烦能换一下”...终于蹭到了后门口,当我看见那熟悉的地面时,我就感觉有一束光明照耀进来,那哪里是公车后门啊。当时在我眼里就是天堂的大门,他许许的打开。而我,这个在地狱炼狱中的人,好像触摸到了上帝伸出的手臂;看到了如来的笑脸;听到了真主的召唤。我兴奋,我快乐,我发狂...一个声音在对我说:“你自由了”。我真想像《勇敢地心》中的主角一样大喊一声“freedom”。
然而“f”还没有发出声,一只手臂横在我的面前,然后转式抓住我的手臂。于是我听到了另一个实实在在的声音:“干什么。”。
“下车啊,老大,不下车,我往这挤干什么?!”我有些不爽的说,现在人真是可笑,这么挤的车我碰你一两下也是无可奈何啊,再说你又不是个娘们,怕什么怕?我当时就这么想。
结果下面的话让我终身难忘:“钱包,把我的钱包还给我!”。
操!操!操!!!!虽然老婆不让我骂人,但是如此情况下我心里照实骂了几下,当然还问候了他的母亲。
但是可惜的就是我这个人太好了。我想,哎,傻B估计什么时候丢了钱包都不知道,现在先忍了吧,咱也别刺激他,慢慢说,这种情况可以理解么。我就说,“我没拿,您搞错了”。注意哦,我说的可是“您”!!!
"唰"公车门关上了,我听到第三个声音--司机的,“要不要报警!”虽然我是被误解的,但是我现在仍然觉得这个司机做的对。
我有些急了,“大哥,要不我把包给你,我们先下去说,我真没拿。”事后我想起这句话,估计这句话也比较像小偷的话吧。
傻X一听到这句话,反而软了。一句话也不说,就是不停的“自摸”。
我都有些发狂了,心里想了各种结果,不是这样我还要去趟派出所吧?哪有这么多时间陪你玩啊。心里一急嘴上就骂开了“你XX,你报不报警,你不报我报。”我心想,老子身份证工作证什么都在身上,满书包装的都可证明我也是一有正当工作的人,借用我女友事后说得话:我鞋都500多,比你钱包的钱多吧~。于是拿起手机--110,心里盘算这怎么给警察说:我是被人误认为是小偷的人,我报警!!!
然而,我妈说过了,人算不如天算~~。
傻X在自摸了一阵后,终于发出了高潮的声音:“我找到了,在包里!对不起啊!”
我当时就蒙了,愣是没反映过来。门一开我就憨憨的下来了。
不对啊,有着么对不起的么,还有这事。我猛得就像冲回去,咬死这人。现在我终于明白了什么叫兽性,就是你失去理智的时候,会用拳头用脚搞定。但是你兽性被召唤出来的时候,就只想咬!!!
很可惜的是,车开走了,我看见车门前一张猥琐的脸傻傻的笑~。这时候你要是我,你就知道怎么会有狙击步枪这种武器了,可惜我也没有。
被误解,我没意见。但是大哥,下次您放钱包的时候,摆脱,求求您了,记住好么!!!

2006年11月24日星期五

1.5. 交互使用Shell

1.5. 交互使用Shell

使用shell的交互功能,就是从登陆开始一直到你注销为止(以输入exit或者输入CTRL-D[5])。在登陆后,你在shell命令行中输入;这些行是以你在终端或工作环境下输入的文本且以回车为结尾的一行。

[5] shell可以被配置为对CTRL-D退出信号无相应。我们推崇这样做,因为CTRL-D 太容易意外触动。查看Chapter 3 中关于此的详细信息。

默认情况下,shell提示符为每个命令提供已美元符号结尾的信息字符,但是你可以通过查看Chapter 3修改所有提示符内容。

1.5.1. 命令、参数和选项

shell命令行由一个或多个单词组成,每个单词由空格或TABs(制表符)区分。每一行的第一单词是命令。其他的(若是有的话)是命令的参数(也叫变量),就是在指明某个命令上如何运行的名称。

举例来说:命令lp myfile由命令lp(打印一个文件)和一个参数myfile组成。lp指定myfile为打印文件的名字。参数一般多为文件名,但是不一定是:在命令mail cam,mail程序则以cam为要发送到的用户名。

选项是特殊类型的参数用于给命令传递所需运行的特殊信息。选项通常是跟随的简单字母;我们说“通常”是因为它遵守手动快捷的规则。命令lp –h myfile 包含选项-h,它告诉lp不要在打印文件前打印“标题页”(banner page)

有时选项是他们自己的参数。譬如lp –d lp1 –h myfile 有两个选项和一个参数。第一个选项是-d lp1,意思是“发送输入到打印机(目的地)教lp1。”第二个选项是和参数是同前一个例子相同的。


1.4. 获得 bash

1.4. 获得 bash

你也许现在已经使用了或未使用bash。你的系统管理员也许聪明的认为不论怎么样他在系统中使用的是“标准”的。你也许甚至不知道还有一个可以使用的shell。

当然知道你现在正在使用的shell很简单。登陆到你的系统在提示符中输入echo $SHELL。你会看见回应中包含sh、csh、ksh或bash分别表示Bourne, C, Korn, 和 bash shell。(There's also a chance that you're using another shell such as tcsh.)

若是你还未使用bash且又想使用它,首先你需要查找是否它最简在你的系统中。只需要输入bash。若是你得到一个由一些信息加上美元符号新提示符(譬如:bash3 $),那么一切都正常,输入exit可以返回你平时的shell。

若是你得到一个“not found”信息,那么你得系统没有安装它。告诉你的系统管理员或者其他懂得的用户,从而获得非正规途径机会在系统中安装某个版本的bash。若是不行,参阅Chapter 11去找到怎样获得某个版本的bash。

当你确定你的系统有bash时,你可以在其他shell中像前面介绍一样输入bash来调用它。However, it's much better to install it as your login shell, i.e., the shell that you get automatically whenever you log in.你可以自行安装。这有为各个UNIX系统所写的使用手册。若是一些功能不能工作(譬如:你输入命令后返回“not found”错误信息或一个空行的相应),你需要停下来拜访你的系统管理员。或者切换到Chapter 12 ,这里我们列出了些简单的方法去切换你的当前shell。

你需要找到bash在你系统的什么地方,如:在哪个目录安装它。你可以通过输入whereis bash(特别是你在使用 C shell )找到它的路径;若是他不工作,试试whence bash,which bash或这个复杂的命令:[3]

[3] 确保你使用正确的引号在以下的命令:’而不是`。

grep bash /etc/passwd | awk -F: '{print $7}' | sort -u


你会看见回应中包含/bin/bash或/usr/local/bin/bash。

将bash设置为登陆shell,输入chsh bash-name,bash-name就是你用whereis(或类似的命令)返回的值。譬如:

% chsh /usr/local/bin/bash


你会得到一个错误消息说shell错误,或要求输入密码。输入你的密码,然后注销后再次登陆就可以开始使用bash。

[4] 考虑到系统安全,只有特定的程序员被容许安装登陆shell。

1.3.History of UNIX Shells

1.3. History of UNIX Shells

在UNIX的历史上,相对于操作系统独立的shell本身也发展出来很多shell,但是只有很少的几个被普遍应用。

第一个卓越的shell是Bourne shell(以其发明人命名:Steven Bourne),它从1979年开始包含于第一个主流UNIX发行版的版本7中。Steven Bourne最出名的是系统中的sh。尽管UNIX从头到尾有了很多很多的变化,但是Steven Bourne依然流行并且本质也未有多少改变。很多UNIX的工具和管理功能都依赖于此。

第一个广泛使用的shell是C shell(或csh)。它是Bill Joy为加州大学柏克利分校软件(BSD)的UNIX 7版本后所写的。

从C shell的名称便可知他的命令操作类似于C语言,是程序员更容易入手学习UNIX系统。它支持很多操作系统特性(譬如:job control; see Chapter 8)且专为BSD UNIX设计,但是它被移植现在的各种UNIX版本中。它也有很多重要的特征(e.g., aliases; see Chapter 3)使其更贴切与普通用户的使用。

最近几年很多其他的shell开始流行。最著名的是Korn shell。它在商业发行版中结合了Bourne和C shell中最好特点,并加上其他许多它自己的特点。[1] Korn shell与bash有很多的相似,都拥有很多的特性使应用更加方便。Bash的特点是它是免费的。Korn shell的其它相关材料请参考Appendix A.

[1] Korn shell 可以随意下载,但是它附带一个许可证表明在某些地方使用是需要付费的。

1.3.1. Bourne Again Shell

Bourne Again shell(以再次感激Steve Bourne命名)创建于GNU组织。[2] GNU组织是由Free Software Foundation (FSF)(免费软件基金会)的Richard Stallman发起,目的是创建统一的UNIX操作系统平台并且替换所有商业发行版UNIX工具且免费发放它们。GNU不仅仅代表新软件,而且引入新的发行方式:copyleft。Copylefted软件可以免费分发或进一步分发(譬如:源代码必须免费发送)

[2] GNU 首字母缩写, GNU's 不是 UNIX。

Bash,正式“出生”在1988-1-10一个星期日并预定为GNU组织的标准shell,Brian Fox写出了第一个bash版本而且一直改进维护它直到1993年。早在1989年Chet Ramey加入并负责修改众多缺陷和很多宜用特征。Chet Ramey是现在bash官方的维护者和拓展者。

为了遵守GNU法则,所有从0.99版本的bash都可以从FSF免费获得。bash进入了所有主流UNIX且迅速成为众多Bourne shell派生版中最流行的一个。它也成为Linux(一个广泛使用的免费UNIX操作系统)中的标准shell,甚至是Apple的 Mac OS X也有它的存在。

在1995年Chet Ramey开始从事发布新版本2.0(于1996年12月23日发布),bash 2.0相对于前一版本(前一版本1.14.7)添加一系列的新特征使其更好的兼容不同的标准。bash 3.0更加强了一些新特征和对标准的支持。

此书描述bash 3.0。它适用于所有前面发布的bash版本。现在版本中的一些特征若是在前些版本不同或是缺少都会在文本中注明。

1.3.2. bash特征

虽然Bourne shell依然被人认为是“标准”shell,bash却日益的变得流行起来。除了它继承了Bourne shell的兼容性外,他还包容了很多C shell 和 Korn shell的优秀特点。

bash命令输入行的可编辑模式是最吸引用户的地方。在命令行里可以编辑使人更容易的返回修改和更改前一个命令,比C shell历史纪录机制更好,而Bourne shell却不能使你做所有这一切。

另外主流的bash特征是提供用户进程管理的功能(job control)。在Chapter 8中会解释,进程管理如何提供你在同一时间关闭、运行和暂停任意一个命令。这个特征几乎完全借鉴与C shell。

Bash最为重要的优势主要在于体现在它的自定制者和编程者上。他拥有很多选项和变量去定制,且它在开发特征方面也值得注目的提供了function(函数)定义,更多的控制特性,整数算法和高级的I/O控制,等等。