操作系统基础 | 2.5 linux组成概述

Shell(壳/命令行解释器)

Shell 是一种专门的程序,用于读取用户输入的命令,并根据这些命令执行相应的程序。Shell 也被称为命令解释器(command interpreter)。

  • 登录 Shell(login shell):指用户首次登录时系统为其启动的运行 Shell 的进程。

在某些操作系统中,命令解释器是内核的一部分;但在 UNIX 系统中,Shell 是一个普通的用户进程。UNIX 系统支持多种 Shell,不同用户(甚至同一用户的不同会话)可以同时使用不同的 Shell。

用户与用户组(Users and Groups)

用户(Users)

  • 系统中的每个用户都有唯一的登录名(username)和对应的数字用户ID(UID)。
  • 每个用户的信息都记录在 /etc/passwd 文件的一行中,内容包括:
    • 用户名
    • 用户ID(UID)
    • 所属的第一个用户组的组ID(GID)
    • 家目录(home directory):用户登录后进入的初始目录
    • 登录Shell:用于解释用户命令的程序名
    • 密码(通常为加密形式),但出于安全考虑,密码一般存储在只有特权用户可读的 shadow 密码文件中。

用户组(Groups)

  • 为了管理和控制对文件及其他系统资源的访问,用户可以被组织到用户组中。
  • 例如,一个项目组的成员可以被加入同一个用户组,以便共享文件。
  • 早期 UNIX 系统中,一个用户只能属于一个组。BSD 及后来的 UNIX 和 POSIX 标准允许用户同时属于多个组。
  • 每个用户组的信息记录在 /etc/group 文件的一行中,内容包括:
    • 组名(唯一)
    • 组ID(GID)
    • 用户列表:以逗号分隔的用户名列表,表示属于该组的用户(不包括那些通过 /etc/passwd 文件的 GID 字段已属于该组的用户)

超级用户(Superuser)

  • 系统中有一个特殊用户,称为超级用户(superuser),拥有系统内的特殊权限。
  • 超级用户的用户ID为0,通常用户名为 root。
  • 超级用户可以绕过系统的所有权限检查。例如,可以访问系统中的任何文件、向任何进程发送信号等。
  • 系统管理员使用超级用户账户执行各种系统管理任务。

单一目录层次结构、目录、链接与文件

Linux 内核维护着一个单一的分层目录结构来组织系统中的所有文件(与 Windows 等操作系统每个磁盘有独立目录树不同)。这个层次结构的顶端是根目录 /,所有文件和目录都是根目录的子孙。

文件类型

  • 普通文件(regular file):普通数据文件。
  • 目录(directory):特殊文件,内容是文件名和对应文件引用的表。
  • 其他类型:还包括设备文件、管道、套接字、符号链接等。

目录与链接

  • 目录是特殊文件,内容是“文件名+引用”的表,这种关联称为链接(link)
  • 一个文件可以有多个链接(即多个名字),可以存在于同一目录或不同目录。
  • 目录可以包含指向文件和其他目录的链接,形成树状层次结构。
  • 每个目录至少有两个特殊条目:
    • . :指向自身
    • .. :指向父目录(根目录的 .. 也指向自身)
  • 符号链接(软链接,soft link)是一个特殊文件,内容是另一个文件的路径名。
  • 当系统调用中指定路径时,内核会自动解析(跟随)符号链接,直到找到目标文件(递归解析,内核会限制递归次数以防死循环)。
  • 如果符号链接指向的目标不存在,则称为悬挂链接(dangling link)
  • 硬链接(hard link)软链接(soft link)是两种不同的链接类型。

文件名(Filenames)

  • 在大多数 Linux 文件系统中,文件名最长可达 255 个字符。
  • 文件名可以包含除斜杠(/)和空字符(\0)以外的任意字符。
  • 建议只使用字母、数字、点(.)、下划线(_)和连字符(-),即字符集 [-._a-zA-Z0-9],这被称为 SUSv3 标准的“可移植文件名字符集”。
  • 避免使用不在可移植字符集内的字符,因为这些字符在 shell、正则表达式等环境下可能有特殊含义。如果必须使用,需要用反斜杠()转义,否则可能无法正确使用。
  • 避免以连字符(-)开头的文件名,因为在 shell 命令中可能被误认为是选项。

路径名(Pathnames)

  • 路径名是由可选的开头斜杠(/)和一系列用斜杠分隔的文件名组成的字符串。
  • 除最后一个部分外,路径中的每个部分都应是目录(或能解析为目录的符号链接),最后一个部分可以是任意类型的文件。
  • 路径名分为两类:
    • 绝对路径名:以斜杠(/)开头,从根目录开始定位文件。例如 /home/mtk/.bashrc/usr/include/
    • 相对路径名:不以斜杠开头,相对于当前工作目录。例如,从 usr 目录访问 types.h 可用 include/sys/types.h,从 avr 目录访问 .bashrc 可用 ../mtk/.bashrc
  • 路径名可以包含 ..,表示上一级目录。

当前工作目录(Current working directory)

  • 每个进程都有一个当前工作目录(current working directory),即进程在目录树中的“当前位置”,相对路径名都是基于这个目录解析的。
  • 进程的当前工作目录由父进程继承。登录 shell 的初始工作目录由 /etc/passwd 文件中的 home 字段指定。
  • 可以用 cd 命令更改当前工作目录。

文件所有权与权限(File ownership and permissions)

  • 每个文件都有一个关联的用户ID(UID)和组ID(GID),分别表示文件的所有者和所属组。
  • 文件的所有权决定了哪些用户可以访问该文件。
  • 系统将用户分为三类:
    1. 文件所有者(user)
    2. 与文件组ID匹配的组成员(group)
    3. 其他所有用户(other)
  • 每类用户有三种权限(共九个权限位):
    • 读(read):允许读取文件内容
    • 写(write):允许修改文件内容
    • 执行(execute):允许执行该文件(如程序或脚本)
  • 目录的权限含义略有不同:
    • 读:允许列出目录内容(文件名)
    • 写:允许修改目录内容(添加、删除、重命名文件)
    • 执行(或称搜索):允许访问目录中的文件(前提是对文件本身也有权限)

文件 I/O 模型

I/O 的通用性

UNIX 系统 I/O 模型的一个显著特点是I/O 的通用性。这意味着同一组系统调用(如 open()read()write()close() 等)可以用于所有类型的文件,包括设备文件。内核会将应用程序的 I/O 请求转换为相应的文件系统或设备驱动操作,从而对目标文件或设备进行实际的 I/O 操作。因此,使用这些系统调用的程序可以对任何类型的文件进行操作。

内核本质上只提供一种文件类型:按字节顺序排列的字节流。对于磁盘文件、磁盘和磁带设备,可以通过 lseek() 系统调用实现随机访问。

许多应用和库将换行符(ASCII 码 10,linefeed)视为一行文本的结束和下一行的开始。UNIX 系统没有专门的文件结束符(EOF),文件结束通过 read() 返回无数据来检测。

文件描述符(File descriptors)

I/O 系统调用通过文件描述符(file descriptor)来引用已打开的文件。文件描述符是一个(通常很小的)非负整数。通常通过 open() 调用获得文件描述符,open() 需要一个路径名参数,指定要进行 I/O 操作的文件。

当进程由 shell 启动时,通常会继承三个已打开的文件描述符: - 0:标准输入(standard input),进程从中读取输入 - 1:标准输出(standard output),进程向其写入输出 - 2:标准错误(standard error),进程向其写入错误信息和异常通知

在交互式 shell 或程序中,这三个描述符通常都连接到终端。在 stdio 库中,它们分别对应于 stdinstdoutstderr

stdio 库

C 语言程序通常使用标准 C 库中的 I/O 函数(即 stdio 库)进行文件 I/O。常用的 stdio 函数包括 fopen()fclose()scanf()printf()fgets()fputs() 等。这些 stdio 函数是建立在底层 I/O 系统调用(如 open()close()read()write() 等)之上的。