第一章 UNIX 基础知识

1.1 Unix体系结构

OS定义为一种软件,它控制计算机硬件资源,提供程序运行环境,一般称其为内核(kernel),它体积小,位于环境中心。

内核的接口为系统调用(system call),共用函数库构建在系统调用上,应用软件既可以使用公用函数库,也可以使用系统调用。shell是一种特殊的应用程序,它为运行其他应用程序提供一个接口。

下图为 UNIX 体系结构:

广义上,OS包括内核和一些软件,例如 Linux 是 GNU 操作系统使用的内核,可以称这种操作系统为 GNU/Linux,但是通常简称为 Linux。所以 Linux 本身有双重含义,内核和操作系统。

1.2 登陆

(1)登录名

用户登陆 UNIX 系统,键入 登录名,再键入 口令。系统在其口令文件(通常是/etc/passwd文件)中查看登录名。

我文件中的内容:

口令文件中的登陆项由7个以冒号分隔的字段组成,他们分别是:

登陆名、加密口令、数值用户ID、数值组、注释字段、起始目录、shell程序

其中,所有OS已将加密口令移到另一个文件中,第6章将说明这种文件以及访问他们的函数。

(2)shell

用户登陆后,用户可以向shell程序键入命令,某些系统会启动一个视窗管理程序,但 最终总会有一个shell程序运行在一个视窗中。

shell是一个命令解释器,它读取用户输入,然后执行命令。

用户通常用终端(交互式shell),有时通过文件(shell脚本,shell script)向shell进行输入。

下图是常见的shell

Steve Bourne在贝尔实验室开发的 Bourne shell。

Bourne-again shell 是GNU shell,所有Linux系统都提供这种shell,它被设计遵循 POSIX 的。

1.3 文件和目录

(1)文件系统

UNIX文件系统是目录和文件组成的一种层次结构,目录的起点称为根(root),名字是 / 。

目录(directory)是一个包含许多目录项的文件。

在逻辑上,可以认为每个目录项都包含一个文件名,文件属性信息(文件类型,文件大小...),stat 和 fstat 可以返回文件属性的一个信息结构。

目录项的逻辑视图与实际存放在磁盘上的方式是不同的。UNIX 文件系统的大多数实现并不在目录项中存放属性,这是因为当一个文件具有多个硬链接时,很难保持多个属性副本之间的同步。到第4章讨论硬链接时,这个问题将很好理解。

(2)文件名

目录中各个名字称为文件名(filename)。

文件名中不能出现斜线(/)和空操作符(null)。因为谢贤用于分隔各文件名构成路径名。空操作符用于终止一个路径名。

创建新目录时会自动创建两个文件名:. 和 .. ,点指向当前目录,点一点指向父目录。在最高层次的根目录中,点一点和点相同。

现在,所有的UNIX系统支持至少 255 各字符的文件名。

(3)路径名

一个或多个斜线分隔的文件名序列构成路径名(pathname),以斜线开头的路径称为绝对路径(absolute pathname),否则称为相对路径(relative pathname)。相对路径名引用相对于当前目录的文件。

// 列出一个目录中所有文件

#include "apue.h"
#include <dirent.h>

int main(int argc, char **argv)
{
   DIR *dp;
   struct dirent *dirp;

   if  (argc != 2)
      err_quit("usage: ls directory_name");
   if  ((dp = opendir(argv[1])) == NULL)
      err_sys("Can‘t open %s", argv[1]);
   while ((dirp = readdir(dp)) != NULL)
      printf("%s\n", dirp->name);
   closedir(dp);
   exit(0);
}

因为各种不同 UNIX 系统目录项的实际格式是不一样的,所以使用函数 opendir, readdir, closedir对目录进行处理。

opendir 函数返回指向 DIR 结构的指针,将这个指针传给 readdir 函数,我们不关心 DIR 结构中包含了什么。然后,在循环中调用 readdir 来读每个目录项。

readdir 函数返回一个指向 dirent 结构的指针,而当目录中已无可读的目录项时则返回 null 指针。在dirent 结构中取出的是每个目录项的名字(d_name)。使用该名字,此后可调用 stat 函数以获得该文件的所有属性。

当程序将结束,它以参数0调用函数 exit,exit终止程序,按惯例,参数0表示正常结束,参数1-255表示出错。

struct dirent 结构如下:

  (4)工作目录

每个进程 都有一个工作目录(working directory),有时称为当前工作目录(current working directory)。所有相对路径名都从工作目录开始解释。进程可以用chdir函数更改其工作目录。

(5)起始目录

登陆时,工作目录设置为起始目录(home directory),该起始目录从口令文件中相应用户的登陆项中取得。

1.4 输入和输出

(1)文件描述符

文件描述符(file descriptor)通常时一个小的非负整数,内核用它标识一个特定进程正在访问的文件。当内核打开一个已有文件或创建一个新文件时,它返回一个文件描述符。在操作文件时,可以使用。

(2)标准输入、标准输出和标准出错

按惯例,每当运行一个新程序时,所有shell都为其打开三个文件描述符:标准输入(standard input)、标准输出(standard output)以及标准出错(standard error)。

如果项 ls 那样没有做什么特殊处理,则这三个描述符都链向终端。

大多数 shell 都提供一种方法,使其中 任何一个或所有这三个描述符都能重定向到某个文件,如:

ls > file.list

(3)不用缓冲的 I/O

函数 open、read、write、lseek以及close提供了不用缓冲的 I/O。这些函数都使用文件描述符。

//  将标准输入复制到标准输出

#include "apue.h"
#define BUFFSIZE 1
int main(void)
{
   int n;
   char buf[BUFFSIZE];

   while ((n = read(STDIN_FILENO, buf, BUFFSIZE)) > 0)
      if (write(STDOUT_FILENO, buf, n) != n)
         err_sys("write error");
   if (n < 0)
      err_sys("read error");

   exit(0);
}

由于键入值的传递是 FIFO结构的,所以无论 BUFFSIZE 设置为什么值,程序都能正常执行,但是执行效率不同。

(2)标准 IO

标准 I/O 函数提供一种对不用缓冲 I/O 函数的带缓冲接口。使用标准 I/O 函数无需担心如何选取最佳的缓冲区大小,例如上面程序中的 BUFFSIZE 常量的大小。

使用标准 I/O 函数的另一个优点是简化了对输入行的处理。例如,fgets函数读一完整的行,而read函数读指定字节数。

在5.4节中,我们将了解到,标准 I/O 函数库提供了使我们能够控制该库所使用的缓冲风格的函数。

// 用标准 I/O 将标准输入复制到标准输出

#include "apue.h"

int main()
{
   int c;

   while ((c = getc(stdin)) != EOF)
      if (putc(c, stdout) == EOF)
         err_sys("output error");
   if (ferror(stdin))
      err_sys("input_err");

   exit(0);
}

EOF是一个常量,在stdio.h 中定义,使用 ctrl + D键入。 标准输入/标准输出 stdin 和 stdout 定义在 stdio.h 中,表示标准输入和标准输出文件。

1.5 程序和进程

(1)程序

程序(program)是存放在磁盘上、处于某个目录中的一个可执行文件。使用6个exec函数中的一个由内核将程序读入存储器,并使其执行。

(2)进程和进程ID

程序的执行实例被称为进程(process)。某些操作系统用任务(task)表示正被执行的程序。

UNIX系统确保每个进程都有一个唯一的数字标识符,称为进程ID(process ID)。进程ID总是一非负整数。

(3)进程控制

有三个用于进程控制的主要函数:fork、exec和waitpid。

//  从标准输入读命令并执行

#include "apue.h"
#include <sys/wait.h>

int main(void)
{
   char buf[MAXLINE];
   pid_t pid;
   int status;

   printf("%% ");
   while (fgets(buf, MAXLINE, stdin) != NULL) {
      if  (buf[strlen(buf) - 1] == ‘\n‘)
         buf[strlen(buf) - 1] = 0;  /* replace newline with null */

      if ((pid = fork()) < 0) {
         err_sys("fork error");
      } else if (pid == 0) {
         execlp(buf, buf, (char *)0);
         err_ret("couldn‘t execute: %s", buf);
         exit(127);
      }

      if  ((pid = waitpid(pid, &status, 0)) < 0)
         err_sys("waitpid error");
      printf("%% ");
   }

   exit(0);
}

fgets从标准输入一次读一行,当键入文件按结束字符EOF(使用 ctrl + D)作为行的第一个字符时,fgets返回一个 null 指针,程序退出。

由于 execlp 函数要求参数以 null 结尾,而不是换行符,所以需要进行替换。

(4)线程和线程ID

通常,一个进程只有一个控制线程(thread),同一时刻只执行一组机器指令,对于某些问题,如果不同部分各使用一个控制线程,那么可简化问题解决。另外,多个控制线程能充分利用多处理器系统的并行性。

同一个进程的线程共享同一地址空间,所以各线程在访问共享数据时需要采取同步措施以避免不一致性。

与进程相同,线程也用ID标识,但是线程ID只在它所属的进程内起作用。

1.6 出错处理

UNIX 函数时,通常返回一个负值,或者 null,而且整形变量 errno 通常被设置为函数有附加信息的一个值。

文件<errno.h>中定义了符号errno和可以赋予它的各种常量。

errno 以前的定义是:

extern int errno;

但是在支持线程的环境中,多个线程共享进程地址,每个线程都有属于自己的局部errno以避免一个线程干扰另一个线程。例如 Linux支持多线程存取 errno,将其定义为:

extern int * __errno_location(void);
#define errno (*__errno_location())

对于errno应当知道两条规则。

第一:如果没有出错,则其值不会被一个例程清楚。因此,仅当函数的返回值指明出错时,才检验其值。

第二:任一函数都不会讲errno值设置为0,在<errno.h>中定义的所有常量都不为0

C标准定义了两个函数,它们帮助打印出错信息。

#include <string.h>
char *strerror(int errnum);
#include <stdio.h>
void perror(const char *msg);

它首先输出msg指向的字符串,然后一个冒号,一个空格,接着时errno值对应的出错信息,最后是一个换行符。

// 示例strerror和perror

#include "apue.h"
#include <errno.h>

int main(int argc, char **argv)
{
   fprintf(stderr, "EACCES: %s\n", strerror(EACCES));
   errno = ENOENT;
   perror(argv[0]);
   exit(0);
}

出错恢复:

可将<errno.h>中定义的各种出错分成致命性和非致命性两类。对于致命性错误,无法执行恢复动作,最多只能在用户屏幕上打印一条出错信息,或写入日志,然后终止。而对于非致命性出错,可以进行处理,大多数非致命性出错本质上是暂时的,如资源短缺。

与资源相关的非致命性出错包括 EAGAIN、ENFILE、ENOBUFS、ENOLCK、ENOSPC、ENOSR、EWOULDBLOCK,有时 ENOMEM也是非致命性,当EBUSY指明共享资源正在使用时,可以将他作为非致命性出错处理,当EINTR中断一慢速系统调用时,可 将它作为非致命性出错处理。

对于资源相关的非致命性出错,一般恢复动作时延迟一些时间,然后再试。

1.7 用户标识

(1)用户ID

口令文件登陆项中的用户ID(user ID)是个数值,它向系统标识各个不同的用户。

系统管理员在确定一个用户登陆名同时,确定用户ID,用户不能更改用户ID。

用户ID为0,是超级用户。

(2)组ID

口令文件登陆项也包括用户的组ID(group ID),它是一个数值。

组被用于将若干用户分到不同的项目组或者部门中去。这种机制允许同组各个成员之间共享资源,而组外用户则不能。

组文件将组名映射为数字组ID,它通常是 /etc/group

使用数字ID是历史上形成的,为的是节省磁盘空间,另外权限校验也比字符串更省时。对于用户而言使用字符串更方便,所以口令文件包含了登陆名和用户ID之间的映射关系。

(3)附加组ID

大多数UNIX系统允许用户属于多个组。

1.8 信号

信号(signal)是通知进程已发生某种情况的一种技术。

进程对于信号有三种选择:忽略,默认方式处理,捕捉。

1.9 时间值

UNIX系统一直使用两种不同的时间值:

(1)日历时间,该值是自 1970年1月1日00:00:00以来国际标准时间(UTC)所经过的秒数累计值(早期称为格林尼治标准时间)。

系统基本数据类型 time_t 用于保存这种事件值。

(2)进程时间,也被称为 CPU 时间,用于度量进程使用CPU资源。进程时间以时钟滴答计算。历史上有每秒50,60或100个滴答。

系统基本数据类型 clock_t 用于保存这种时间值。

当度量一个进程的执行时间时,UNIX系统使用三个进程时间值:

时钟时间,用户CPU时间,系统CPU时间。

时钟时间:进程运行时间总量。

用户CPU时间:执行用户指令所用的时间。(进程在用户空间的时间)

系统CPU时间:执行内核程序所经历的时间。(进程在内核空间的时间)

要获进程的三种时间,只需要执行命令 time(1)。

原文地址:https://www.cnblogs.com/yangxinrui/p/9723945.html

时间: 2024-10-12 01:54:39

第一章 UNIX 基础知识的相关文章

APUE第一章 UNIX基础知识

前语:本人是半路出家做程序员,实际上应付平时工作中的业务还可以,但是基础知识实在薄弱,当然也跟中国计算机教育有关系,平时跟同事聊天,实际上就算是科班出身,对于计算机本身的了解也知之甚少,因此在毕业两周年到来的时候,给自己确定了以后的技术学习方向,同时也决定了将基础部分补充起来,特来CSDN开这个专题,去学习程序员圣经般著作-<UNIX高级环境编程>,这本书也是被某个同事经常提起,书本比较厚,但是不能操之过急,但是也不要指望一次性就能学完学透,没事回来看看,总有收获,自勉之. 一.UNIX体系结

UNIX环境高级编程学习笔记(第一章UNIX基础知识)

总所周知,UNIX环境高级编程是一本很经典的书,之前我粗略的看了一遍,感觉理解得不够深入. 听说写博客可以提高自己的水平,因此趁着这个机会我想把它重新看一遍,并把每一章的笔记写在博客里面. 我学习的时候使用的平台是Windows+VMware+debian,使用secureCRT来连接(可以实现多个终端连接). 因为第一章是本书大概的描述,所以第一章的我打算写得详细一点,而且书本的原话占的比例会比较多,重点的东西会用粗体显示出来. 1.1  引言 所有操作系统都为他们所运行的程序提供服务.典型的

自学:Unix环境高级编程 第一章 Unix基础知识

1.2 Unix体系结构 内核(kernel):控制计算机硬件资源,提供程序运行环境. 系统调用(system call):内核的接口. 公用函数库构建在系统调用接口之上. 应用程序既可使用公用函数库,也可使用系统调用 shell是一个特殊的应用程序,为运行其他应用程序提供了一个接口. 1.3 登录    1.登录名 系统在其口令文件(通常是/etc/passwd文件)中查看登录名. 例如:sar:x:205:105:Stephen Rago:/home/sar:/bin/ksh 口令文件中的登

第一章 Unix基础知识

unix环境高级编程,尤晋元,2000年 只是把书里的代码敲一遍跑一下,熟悉一下书里的东西,没什么特别的: #include <stdio.h> #include <stdlib.h> #include <unistd.h> // list directory content int ls(int, char**); // copy input to output int IO_Nobuffer(); int standardio(); int shell(int, c

APUE学习笔记:第一章 UNUX基础知识

1.2 UNIX体系结构 从严格意义上,可将操作系统定义为一种软件(内核),它控制计算机硬件资源,提供程序运行环境.内核的接口被称为系统调用.公用函数库构建在系统调用接口之上,应用软件即可使用公用函数库,也可使用系统调用.shell是一种特殊的应用程序,它为运行其他应用程序提供了一个接口 从广义上,操作系统包括了内核和一些其他软件,这些软件使得计算机能够发挥作用,并给予计算机以独有的特性(软件包括系统实用程序,应用软件,shell以及公用函数库等) 1.3  shell shell是一个命令行解

第一章 计算机基础知识

第一章 计算机基础知识 第一部分 概述 1.1946年2月15日,第一台计算机 ENIAC 2.物理原件(电子原件) 第一代:电子管.第二代:晶体管.第三代:中小规模集成电路.第四代:超大规模集成电路.第五代:超导材料.第六代:人工智能.#考试考到第四代. 3.计算机的分类 巨型机,大型机,中型机,小型机,微型机 现在的巨型机也是存在的 4.微处理器(CPU.中央处理器)由控制器.寄存器.运算器组成 第二部分 微机系统的组成 CPU>内存>外存 #速度 CPU和内存之间有一个CACHE,叫做高

高项3.7日第一次课,第一章信息化基础知识与第二章信息系统服务管理梳理

第一章 信息化的基础知识 1.国家信息化体系要素: 主要包括6要素,信息技术应用(龙头).信息资源(关键).信息网络(必要手段).信息技术产业(基础).信息化人才(成功之本).信息化法规政策和规范(保障). 2.电子政务: 电子政务建设的指导原则: (1)统一规划,加强领导. (2)需求主导,突出重点. (3)统一规划,拉动产业. (4)统一标准,保障安全. 主要任务: (1)电子政务网络由政务内网和政务外网构成,两网之间物理隔离,政务外网与互联网之间逻辑隔离.政务内网主要是副省级以上政务部门的

第一章 Shell基础知识

1.1 简介 Shell是一个C语言编写的脚本语言,它是用户与Linux的桥梁,用户输入命令交给Shell处理,Shell将相应的操作传递给内核(Kernel),内核把处理的结果输出给用户. 下面是处理流程示意图: Shell既然是工作在Linux内核之上,那我们也有必要知道下Linux相关知识. Linux是一套免费试用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户.多任务.支持多线程和多CPU的操作系统. 1983年9月27日,Richard Stallman(理查德

第一章 Python基础知识

1.1 介绍  1.1.1 特点 Python是一种面向对象.解释型计算机程序设计语言.语法简洁清晰,强制用空白符作为语句缩进. Python具有丰富和强大的库,又被称为胶水语言.能把其他语言(主要C/C++)写的模块很轻松的结合在一起. 1.1.2 应用领域 Web网站:有很多优秀的开源Web框架,比如Django(最流行).Tornado(轻量级.异步).Flask(微型).Web.py(简单)等. 数据采集:有好用的http库,比如urllib2.requests等.还有高级的屏幕爬取及网