您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 公司方案 > unix环境高级编程--第1章 UNIX基础知识
发信人:scircle(yuanyuan),信区:Security标题:unix环境高级编程--第1章UNIX基础知识发信站:BBS水木清华站(ThuMar2316:41:472000)〓引言所有操作系统都向它们运行的程序提供服务。典型的服务是执行一道新程序、打开一个文件、读一个文件、分配一个存储区、获得当前时间等等,本书的焦点是说明各种Unix操作系统版本所提供的服务。以严格的步进方式,不超前引用尚未说明过的术语来说明Unix几乎是不可能的(可能也会是令人厌烦的)。本章从程序设计人员的角度快速周游Unix,我们将对书中引用的一些术语和概念进行简要的说明并给示实例。在以后各章中,我们将对这些作更详细的说明。本章也对不熟悉Unix的程序设计人员介绍、概述Unix提供的各种服务。〓登录(Logging登录名当我们向Unix系统登录时,先键入登录名,然后键入口令字。系统在其口令文件,通常是/etc/passwd文件中查看我们的登录名。在口令文件中的登录项,由7个以冒号分隔的字段组成:登录名,加密口令字,数字用户ID(224),数字组ID(20),注释字段,起始目录(/home/stevens),以及shell程序(/bin/ksh)。很多比较新的系统已将加密口令字移到另一个文件中。在第六章,我们将说明这种文件,以及存取它们的函数。我们登录后,系统先典型地显示一些消息,然后我们就可以向shell程序键入命令。shell是一个命令行解释器,它读用户输入,然后执行命令,用户通常用终端,有时则通过文件(称为shell脚本)向shell进行输入。常用的shell是:·Bourne系统从口令字文件中与我们相关的登录项的最后一个字段了解到应为我们执行那一个shell。自Version7(第七版)以来,一直在使用Bourneshell,几乎每一个现存的Unix系统都提供Bourneshell。CShell是在Berkeley(贝克莱)开发的,所有BSD版本都提供这种shell。另外,Cshell也由AT&T系统和系统VR4(SVR4)提供,(在下一章,我们将对这些不同的Unix版本作更多说明。KornShell是Bourneshell的后继者,它由SVR4提供。Kornshell在大多数Unix系统上运行,但在SVR4之前,通常它需要另行购买,所以没有其它两种shell流行。Bourneshell是由SteveBourne在Bell实验室中开发的其控制流结构使人想起AlgShell是在贝克莱由BillJoy完成的,其基础是第6版shell(不是Bourneshell)。其控制结构很象C语言,它支持了一些Bourneshell没有提供的功能-作业控制,历史机制和命令行编辑。Kornshell是由DavidKorn在Bell实验室中开发的,它兼容Bourneshell,并且也包含了使Cshell非常流行的一些功能-作业控制、命令行编辑等。在全书中,我们都会使用这种形式的注释以说明历史沿革,并对不同的Unix实现进行比较。当说明了历史缘由后,常常使得采用一种特定实现技术的理由变得清晰起来。在全书中,我们将使用很多shell实例,以执行我们已开发的程序,其中将应用Bourneshell和Kornshell都具有的功能。〓文件和目录文件系统Unix文件系统是目录和文件的一种分层次的安排,目录的起点称为根(root),其名字是一个字符/。一个目录是一个包含目录项的文件,在逻辑上,我们可以认为每个目录项都包含一个文件名,同时还包含说明该文件属性的信息。文件属性是:文件类型,文件长度,文件属主,文件的许可权(例如,其他用户能否存取该文件?)文件的最后修改时间等。stat和fstat函数返回一个包含所有文件属性的信息结构。在第四章中,我们将详细说明文件的各种属性。文件名一个目录中的各个名字称为文件名。不能出现在文件名中的字符只有两个,它们是斜线(/)和空操作(null)字符,斜线分隔构成路径名(在下面说明)的各文件名,空操作符则终止一个路径名,尽管如此,一个好的习惯是只使用印刷字符的一个子集作为文件名字符(只使用子集的理由是:如果在文件名中使用了某些shell特殊字符,则必须使用shell的引号机制来引用文件名)。当创建一个新目录时,自动创建了两个文件名:称为点)和称为点-点)。点引用当前目录,点-点则引用文目录。在最高层次的根目录中,点-点与点相同。某些Unix文件系统限制文件名的最大长度为14个字符,BSD版本则将这种限制扩展为255个字符。-路径名0个或多个以斜线分隔的文件名序列(可以任选地以斜线开头)构成路径名,以斜线开头的路径名称为绝对路径名,否则称为相对路径名。实例不难列出一个目录中所有文件的名字,程序是ls(1)命令的主要实现部分程序〓列出一个目录中的所有文件ls(1)这种表示方法是Unix的惯用方法,用以引用Unix手册集中的一个特定项。它引用第一部分中的ls项,各部分通常用数字1至8表示,在每个部分中的各项则按字母顺序排列。在全书中,我们都假定你有一份你所使用的Unix系统的手册。较早的Unix系统把8个部分都集中在一本Unix程序手册中,现在的趋势是把这些部分分别按排在不同的手册中:一本是由用户使用的,一本是由程序员使用的,一本是由系统管理员使用的等等。某些Unix系统把一个给定部分中的手册页又用一个大写字母进一步分成若干小部分,例如,AT&T〔1990e〕中的所有标准I/O函数都被指明在3s部分中,例如fopen(3s)。某些Unix系统,例如以Xenix为基础的系统,不同数字将手册分成若干部分,代之,它们用C表示命令(第1部分),S表示服务(通常是第2、3部分)等等。如果你有联机手册,则阅看ls命令手册页的方法一般是:man1程序只打印一个目录中各个文件的名字,不显示其它信息,如若该源文件名为则我们可以用下面的命令对其进行编辑,编辑的结果送入系统默认名为的可执行文件名:cc某种样本输出是:$$/var/spool/mqucan′topen/var/spool/mqueue:Permission$can′topen/dev/tty:Nota在全书中,我们都将以这种方式表示我们输入的命令以及其输出:我们输入的字符以这种字体表示程序输出则以另一种字体表示。如果我们欲对输出添加注释,则以表示注释,在我们输入之前的美元符号($)是shell打印的提示符,我们总是将shell提示符显示为$。注意,列出的目录项不是以字母序排列的,ls命令本身则一般以字母序列出目录项。在这20行程序中,有很多细节可以考虑:·首先,其中包含了一个我们自己的头文件。在本书中,几乎每一道程序都包含此头文件。它包含了某些标准系统头文件,定义了许多常数及函数原型,这些都将用于本书的各个例子中,此头文件包含在附录B中。·main函数的说明使用了ANSIC标准所支持的新风格。(在下一章中,我们将对ANSIC作更多说明。·我们取命令行的第1个参数argv〔1〕作为要列表的目录名。在第七章中,我们将说明main函数是如何被调用的,程序如何存取命令行参数和环境变量。·因为各种不同Unix系统的目录项的实际格式是不一样的,所以我们使用函数opendir,readdir和closedir处理目录。·opendir函数返回指向DIR结构的指针,并将该指针传向readdir函数。我们并不关心DIR结构中包含了什么。然后,我们在循环中调用readdir,以读每个目录项。它返回一个指向dirent结构的指针,而当目录中已无目录项可读时则返回null指针。我们在dirent结构中取出的只是每个目录项的名字(d[CD#*2]name)。使用该名字,我们此后就可调用stat函数节)以决定该文件的所有属性。·调用了两个我们自编的函数对错误进行处理:err-sys和err-quit。我们从上面的输出中可以看到,err-sys函数打印一条消息,说明遇到了什么类型的错误。(Permissiondenied或Notadirectory(许可权拒绝或不是一个目录。这两个出错处理函数也在附录B中说明,我们也将在节中更多地叙述出错处理。·当程序将结束时,它以参数O调用函数exit。函数exit终止一道程序。按惯例,参数O的意思是正常结束,参数值1~255则表示出了一种错。在节中,我们将说明一道程序(例如一个shell或我们所编写的程序)如何获得它所执行的另一道程序的exit状态。工作目录(Working每个进程都有一个工作目录(有时称为当前工作目录)。所有相对路径名都从工作目录开始解释。进程可以用chdir函数更改其工作目录。例如,相对路径名doc/memo/joe指的是文件joe,它在目录memo中,而memo又在目录doc中,doc则应是工作目录中的一个目录项。从该路径名可以看出,doc和memo都应当是目录,但是我们却不清楚joe是文件还是目录。路径名/urs/Lib/Lint是一个绝对路径名,它指的是文件(或目录)Lint,而Lint在目录lib中,lib则在目录usr中,usr则在根目录中。起始目录(Home当我们登录时,工作目录设置为起始目录,该起始目录从口令字文件(见节)中我们的记录项中取得。〓输入和输出文件描述符(File文字描述符是一个小的非负整数,系统核用以标识一个特定进程正在存访的文件。无论何时,系统核打开一个现存文件或创建一个文件,它就返回一个文件描述符。当读、写文件时,我们就使用它。标准输入、标准输出和标准出错按惯例,每当运行一道新程序,所有的shell,都与其打开三个文件描述符:标准输入、标准输出以及标准出错。如若象简单命令ls那样,没有做什么特殊处理,则所有这三个都连向我们的终端。大多数shell都提供一种方法,使任何一个或所有这三个描述符都能重新定向到某一个文件,例如:执行ls命令,其标准输出重新定向到名为的文件点。不用缓存的函数open、read、write、lseek以及close提供了不同缓存的I/O。这些函数都用文件描述符进行工作。实例如若我们愿望从标准输入读,并写向标准输出,则程序可以复制任一Unix文件。程序〓将标准输入复制到标准输出头文件中包含了此头文件)及两个常数STDIN-FILENO和STDOUT-FILENO是POSIX标准的一部分(在下一章,我们将对此作更多的说明)。很多Unix系统服务的函数原型,例如我们调用的read和write都在此头文件中。函数原型也是ANSIC标准的一部分,我们将在本章的稍后部分对此作更多说明。两个常数STDIN-FILENO和STDOUT-FILENO定义在d头文件中,它们指定了标准输入和标准输出的文件描述符。它们的典型值是0和1,但是为了可移植性,我们将使用这些新名字。在节中,我们将详细地讨论BUFSIZE常数,说明各种不同值将如何影响程序的效率。但是不管该常数的值如何,此程序总能复制任一Unix文件。read函数返回读得的字节数,此值用作为要写的字节数。当到了文件的尾端时,read返回0,程序停止执行。如果发生了一个读错误,read返回-1,出错时,大多数系统函数返回-1。如若编辑读程序,其结果送入标准的文件,并以下列方式执行它:那么,标准输入是终端,标准输出则重新定向至文件data,标准出错也是终端。如果此输出文件并不存在,则shell创建它。在第三章中,我们将更详细地说明不用缓存的I/O函数。标准标准I/O函数提供一种对不用缓存的I/O函数的带缓存的界面。使用标准I/O使我们无需担心如何选取最佳的缓存长度,例如程序中的BUFSIZE常数。另一个使用标准I/O函数的优点与处理输入行有关(常常发生在Unix的应用中)。例如,fgets函数读一完整的行,而另一方面,read函数读指定字节数。我们最熟悉的标准I/O函数是printf。在调用printf的程序中,我们总是包括std通常包括在中),因为此头文件包括了所有标准I/O函数的原型。实例程序的功能类似于调用read和write的前一道程序,我们将在中对程序作更详细的说
本文标题:unix环境高级编程--第1章 UNIX基础知识
链接地址:https://www.777doc.com/doc-3368407 .html