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。
前四个比较易懂。剩下的两个使用了特殊的目录称为..(两个点),意思是“当前目录的父目录”。每一个目录都有一个,它是普遍且含路径到结构中的上一层目录—也被称为父目录。[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 将更详细的解释。
在最初的通配符例子里,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。
没有评论:
发表评论