操作系统基础 | 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)。
- 一个文件可以有多个链接(即多个名字),可以存在于同一目录或不同目录。
- 目录可以包含指向文件和其他目录的链接,形成树状层次结构。
- 每个目录至少有两个特殊条目:
.
:指向自身..
:指向父目录(根目录的..
也指向自身)
符号链接(Symbolic 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),分别表示文件的所有者和所属组。
- 文件的所有权决定了哪些用户可以访问该文件。
- 系统将用户分为三类:
- 文件所有者(user)
- 与文件组ID匹配的组成员(group)
- 其他所有用户(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
库中,它们分别对应于 stdin
、stdout
和
stderr
。
stdio 库
C 语言程序通常使用标准 C 库中的 I/O 函数(即 stdio 库)进行文件
I/O。常用的 stdio 函数包括
fopen()
、fclose()
、scanf()
、printf()
、fgets()
、fputs()
等。这些 stdio 函数是建立在底层 I/O 系统调用(如
open()
、close()
、read()
、write()
等)之上的。