Linux 杂项

Linux 系统层次结构

202402152237065.png

内核交互

内核交互的定义: 内核交互是指用户空间程序请求操作系统内核执行某些操作的过程。由于内核控制着计算机的所有硬件资源,因此任何需要访问或控制这些资源的操作都需要通过内核来完成。

内核的作用: 内核负责管理计算机的硬件资源,包括但不限于:

  • CPU 调度
  • 内存管理
  • 外部设备(如键盘、鼠标、显示器等)
  • 进程和线程的创建、调度和管理
  • 网络通信

何时需要与内核交互: 当程序需要执行以下操作时,通常需要与内核交互:

  • 文件系统访问和管理
  • 外部设备的输入/输出操作
  • 动态内存分配(如使用 mallocfree
  • 进程间通信或网络通信

不需要内核交互的操作: 并非所有程序操作都需要内核参与。如果操作仅限于用户空间内存内的数据变化,内核通常不需要介入。例如:

  • 程序内的普通函数调用
  • 基本的算术运算(加、减、乘、除)
  • 变量的声明和赋值
  • 控制流语句(如循环和条件判断)

与内核交互的三种方式

在与 Linux 内核进行交互时,有三种主要方式:

  1. 系统调用:这是最基本、最直接的方式,也是与内核交互的最终和唯一手段。系统调用为用户空间程序提供了一种触发内核执行特定功能的机制。
  2. POSIX 标准库函数:这些是间接的内核交互手段,它们通过系统调用来实现。POSIX 标准定义了一组操作系统应该提供的接口,以确保应用程序的可移植性。这些库函数非常常用,因为它们为开发者提供了一种更高级、更易于使用的与内核交互的方式。
  3. Shell 应用:Shell 本身是一种应用程序,提供了一种用户友好的接口来执行命令和脚本。Shell 应用程序提供的内核交互可能是基于系统调用的,也可能是基于库函数的。用户可以通过 Shell 命令来执行文件操作、进程控制等操作,这些操作最终会通过系统调用来实现。

这三种方式各有优势,开发者可以根据需要选择最合适的方法来与 Linux 内核交互。系统调用提供了底层的、强大的功能,而 POSIX 标准库函数和 Shell 应用则提供了更易于使用的抽象层。

系统调用

系统调用:系统调用是内核提供给用户空间程序的一种服务,允许应用程序通过这些调用请求内核执行特定的操作。在 Linux 和类 Unix 操作系统中,系统调用通常以 C 语言风格暴露给用户空间,因为这些系统的内核大多是用 C 语言编写的。

系统调用遵循 POSIX 标准,这意味着它们在类 Unix 系统间具有一致性,但通常不能在 Windows 平台上使用。

库函数

库函数与系统调用的关系: 库函数是对系统调用的封装,它们提供了一种更高级、更易于使用的与内核交互的方式。ISO C 库函数,如 printfscanfmallocfopen 等,背后都是通过系统调用来实现的。

为什么需要库函数

  1. 跨平台性:库函数封装了系统调用,使得相同的库函数可以在不同平台上实现相同的功能,从而实现跨平台的代码可移植性。
  2. 简化复杂性:系统调用通常只提供基础的交互手段,而库函数可以在此基础上实现更复杂、更高级的功能,简化了应用程序的开发。

此外,一些库函数可能实现的功能非常简单,不需要进行系统调用,这进一步扩展了库函数的应用范围。

Shell

Shell 的定义: Shell 是一种命令行解释器应用程序,它提供了用户与操作系统之间的接口。用户可以通过在 Shell 中输入命令,由 Shell 解释并执行相应的程序或操作。

Shell 的功能

  • Shell 接收用户输入的命令,并根据这些命令执行特定的应用程序或系统操作。
  • 它允许用户浏览文件系统、管理文件和目录、运行程序以及执行各种系统管理任务。

常见的 Shell 应用程序

  • bash(Bourne Again Shell):是 Linux 和许多类 Unix 系统上的默认 Shell,以其强大的脚本编写能力和用户友好性而广受欢迎。
  • zsh(Z Shell):是 bash 的一个扩展,提供了更多的功能和改进,包括更好的命令补全、会话管理和更高级的脚本编程特性。

Shell 的应用场景

  • Shell 在系统管理和自动化任务中发挥着重要作用。系统管理员和开发人员经常使用 Shell 脚本来自动化复杂的工作流程。
  • Shell 也是学习操作系统原理和进行基本系统操作的重要工具。

Shell 的发展:早期的 Mac OS 终端使用 bash 作为其默认 Shell 解释器。19 年后的 Mac OS 终端迁移到 zsh,以利用其增强的功能。

Linux 文件管理系统

虚拟文件系统 VFS

虚拟文件系统是建立在物理文件系统上层的,给用户使用的文件系统。它的特点是各平台统一,操作简单。

虚拟文件系统 VFS 和物理文件系统的映射关系

硬链接(Hard Link): 硬链接是物理文件系统中的一个特性,它允许多个文件名(目录项)指向同一个文件的 inode。每个文件系统都有一个记录硬链接数量的机制。例如,如果文件 A 有两个硬链接,表示有两个不同的文件名指向文件 A 的相同数据。

硬链接的特点

  • 硬链接与符号链接(Symbolic Link)不同,后者是一个指向另一个文件的路径的文件。
  • 硬链接共享相同的 inode(在类 Unix 系统中用于存储文件元数据的数据结构),因此它们具有相同的文件大小、权限、时间戳等属性。
  • 删除硬链接不会影响被链接的文件,只有当所有指向该文件的硬链接都被删除后,文件数据才会被删除。

VFS 与硬链接的关系

  • VFS 通过抽象层管理硬链接,使得操作系统和应用程序无需关心底层物理文件系统的实现细节。
  • 当应用程序通过 VFS 接口操作文件时,VFS 负责处理硬链接的逻辑,确保文件操作的正确性和一致性。

硬链接在文件系统中是一种有用的特性,它允许用户以不同的路径访问同一个文件,同时保持文件的完整性和一致性。

202402250949508.png

VFS 中的硬链接数存储: 在虚拟文件系统(VFS)中,即使文件系统抽象层也存储硬链接数的信息。这是因为 VFS 需要维护文件的元数据,包括硬链接的数量。例如,文件 file1 和 file2 可能都是指向同一物理文件的硬链接,它们的硬链接数都是 2。

存储硬链接数的原因: 存储硬链接数是为了跟踪有多少个文件名指向同一个文件数据。这与引用(指针)计数法类似,当存在指针指向一块内存时,内存不会被自动释放;当没有指针指向时,内存会被自动释放。这是一些编程语言内存自动管理的核心机制。

在文件系统中,当硬链接数降至 0 时,意味着没有文件名指向该文件数据,文件系统会决定释放该文件占用的磁盘空间,从而真正删除该文件。

在 Linux VFS 中,每个目录都隐含地包含两个特殊的目录项,即使在空目录中也是如此:

  • .(单个点):这个文件代表当前目录的引用。通过它,用户和程序可以访问当前目录内的文件和子目录。
  • ..(双点):这个文件指向当前目录的父目录。它允许用户和程序从当前目录移动到其上级目录。

这两个特殊的目录项是 Linux 文件系统设计的一部分,它们帮助用户和程序更容易地导航文件系统。

文件系统和文件的存储

inode 的定义: inode 是文件系统中用于存储文件元数据的数据结构。它是虚拟文件系统(VFS)到物理文件系统的入口,可以被理解为文件的“开头”或索引。

inode 的作用

  • inode 包含了文件的元数据,如文件大小、权限、时间戳、数据块位置等,但不包含文件名。文件名和 inode 之间通过目录项进行关联。
  • 在同一文件系统中,多个 VFS 中的文件可以映射到同一个物理文件系统中的文件。这种情况下,这些文件会共同指向同一个 inode,共享同一个 inode 结点。

inode 的共享:当多个文件名指向同一个 inode 时,它们实际上是引用了同一个文件。这种特性在硬链接(hard links)中得到体现,硬链接允许多个文件名共享相同的文件数据。

查询 inode:在 Linux 系统中,可以使用 ls -i 命令来查询当前目录下所有文件的 inode 编号。如果两个文件的 inode 编号相同,这意味着它们指向同一个 inode,即它们是同一个文件的不同引用。

文件名的存储位置: 文件名并不存储在 inode 中,因为 inode 是文件系统的一个通用数据结构,它包含了文件的元数据信息,如文件大小、权限、时间戳等,但并不包含文件名。

为什么 inode 不能存储文件名

  • 文件名是与 VFS(虚拟文件系统)相关的概念,与物理文件系统的具体实现无关。
  • 硬链接的存在表明,多个文件名可以指向同一个 inode,共享相同的文件数据和元数据。因此,文件名不能存储在 inode 中,因为它们不是共享的,而是每个链接独有的。

文件名的存储:文件名必须存储在 VFS 中的某个结构里。在 UNIX 和类 UNIX 系统中,文件名通常与目录项(directory entry)关联,目录项包含了文件名和指向该文件 inode 的指针。

查询文件名:用户可以通过查看目录的内容来获取文件名。文件系统通过维护一个目录结构,将文件名映射到对应的 inode。

相关指令

ls

cp

cp 指令执行的文件复制cp 指令复制文件时,是对物理文件系统的操作。这意味着它会创建文件的新副本,包括新的 inode 和 inode 背后的文件数据块。

复制文件夹的过程: 当使用 cp 指令复制文件夹时,该过程需要递归地深入到每一个子目录中,并对该目录下的所有子文件进行复制操作。这是因为文件夹包含其他文件和可能的子文件夹,这些都需要被复制到目标位置。

递归复制的必要性: 为了确保文件夹内的所有内容都被复制,必须使用 -r(或 --recursive)选项。没有这个选项,cp 指令将无法递归地复制子目录,从而导致复制操作失败。

mv

mv 指令的用途mv 指令的主要作用是改变文件或目录的位置,或者重命名它们。当使用 mv 指令移动文件时,实际上是在文件系统中更新文件的路径和名称。

重命名文件mv 指令可以用于重命名文件,因为文件的路径是文件名的一部分。例如,将文件从一个名称改为另一个名称,同时保持其在文件系统中的位置不变。

移动目录: 当 mv 指令用于目录时,它可以将目录从一个位置移动到另一个位置,成为另一个目录的子目录。

目录的移动特点

  • 目录移动不会覆盖目标位置的现有目录,除非目标目录是空的或者目标目录存在但与源目录具有相同的 inode 编号(在某些特殊情况下可能发生)。
  • 如果目标位置已经存在一个同名目录,mv 指令将不会执行覆盖操作,而是会报错。

202402251515834.png

目录文件的结构

目录文件的结构: 目录文件在虚拟文件系统(VFS)和物理文件系统中都有其存储结构。在物理文件系统中,目录文件存储的是其下所有子文件和子目录的相关信息。

目录项(Directory Entry)

  • 每个子文件和子目录在目录文件中都对应一个目录项,这些目录项包含了文件名和文件的 inode 编号。
  • 在 C 语言中,目录项通常由 struct dirent 结构表示。

目录项的组织

  • 为了便于理解和操作目录项,可以将其组织关系简化为单链表的形式。
  • 然而,现代操作系统为了提高文件系统操作的性能,通常采用更复杂和高效的数据结构,如树形结构。

文件系统的内部结构

  • 不同的文件系统可能采用不同的数据结构来组织目录项。例如:
    • NTFS 文件系统通常采用 B+树(多路自平衡搜索树)的形式。
    • ext4 文件系统一般采用哈希树(HTree)。

目录项存储了文件的文件名和 inode 编号,这是文件系统中查找文件的关键信息。

202402251553735.png

202402251559406.png

202402251600839.png

硬链接的限制: 硬链接不能用于目录文件。这是因为硬链接通过指向相同的 inode 来实现文件的共享,而目录文件的 inode 包含了指向其子目录项的列表。

目录结构的保护

  • 如果允许硬链接到目录,那么在目录项的结构中可能会出现“环”,即目录项相互引用,形成一个循环。
  • 这种环的存在会破坏目录的结构,导致无法通过目录项遍历到达文件系统中的其他部分。

为了防止这种情况,文件系统不允许对目录创建硬链接。相反,可以使用符号链接(也称为软链接)来指向目录,因为符号链接是指向目标文件或目录的路径的引用,而不是指向 inode 的直接链接。

硬链接仅适用于普通文件,不适用于目录文件,以维护文件系统的结构完整性和避免潜在的循环引用问题。

软连接与目录: 软连接可以链接到目录文件,这是因为软连接具有自己的 inode,它不会与目标目录共享 inode。因此,软连接不会导致目录结构中出现环,也不会破坏目录的结构。

软连接的工作原理

  • 软连接的 inode 存储了软连接文件的元数据信息。
  • 与普通文件一样,软连接也有一个数据块,该数据块存储了软连接的内容,即目标文件或目录的路径名字符串。

软连接的操作

  • 当在文件系统中操作软连接文件时,文件系统首先会读取软连接文件的数据块,以获取其中存储的目标路径名字符串。
  • 接着,文件系统会根据这个路径名字符串查找目标文件或目录,并执行相应的操作。

软连接的优点:软连接提供了一种灵活的方式,允许用户通过不同的路径名访问同一个文件或目录,而不需要复制文件或目录的数据。

软连接可以安全地链接到目录,因为它们不会影响文件系统的结构完整性。软连接的透明性和灵活性使其成为文件系统操作中的一个重要特性。

文件权限

目录文件的权限

目录文件的读权限

  • 拥有目录文件的读权限意味着用户可以读取目录项(directory entries),即目录下的文件名和 inode 编号。
  • 这允许用户通过 ls -a 等命令列出目录中的文件信息。如果没有读权限,用户将无法查看目录中包含的文件。

目录文件的写权限

  • 拥有写权限意味着用户可以修改目录项的结构,例如添加、删除或修改目录中的文件和子目录。
  • 因此,创建、删除、重命名、复制、移动文件等操作都需要目录的写权限。
  • 受写权限影响的命令包括 mkdirrmdirmvcp 等。

目录文件的可执行权限

  • 目录的可执行权限是访问目录内容的基础。没有执行权限的目录,用户将无法进入、查看或操作目录中的文件。
  • 如果用户没有目录的可执行权限,即使拥有文件的读或写权限,也无法访问该目录下的文件。

目录文件的权限决定了用户对目录内容的操作能力。读权限允许查看目录中的文件列表,写权限允许修改目录内容,而可执行权限则是进入和操作目录的基础。

读权限 (r):普通文件的读权限允许用户查看文件的内容。这意味着用户可以读取文件的数据。

目录的读权限与文件访问:访问某个目录下的文件并不需要该目录的读权限。文件内容不是存储在目录项中的,因此查看文件内容只需要目录具有执行权限。

写权限 (w):普通文件的写权限允许用户修改文件的内容。这意味着用户可以编辑或更改文件的数据。

文件操作与目录权限:文件的删除、重命名等操作实际上受目录的写权限控制,而不是文件本身的写权限。

执行权限 (x):执行权限允许用户运行文件作为一个程序或脚本执行。如果用户没有对文件的执行权限,即使文件是一个可执行程序或脚本,用户也无法直接运行它。

执行权限的实际意义:如果文件本身不是可执行程序或脚本,那么即使赋予它执行权限,这个权限也没有实际作用。

chmod

chmod 是 “change mode” 的缩写,其中 “mode” 在计算机文件系统中特指文件或目录的权限设置。chmod 命令允许用户修改文件或目录的访问权限,以控制谁可以读、写或执行它们。

在使用 shell 命令改变文件或目录的权限时,推荐使用直观的 “文字设定法”。这种方法使用字母 u(用户)、g(组)、o(其他)和 a(所有)来指定权限的接收者,以及 +(添加)、-(删除)和 =(赋予)来指定权限的操作。

chmod 命令支持四种用户类别:

  1. u(用户):代表文件的所有者(owner),使用 u 可以修改文件所有者的权限。
  2. g(组):代表文件所属的用户组(group),使用 g 可以修改该组用户的权限。
  3. o(其他):代表除了文件所有者和组用户之外的其他用户,使用 o 可以修改这些用户的权限。
  4. a(所有):代表所有用户,使用 a 可以同时修改用户、组和其他用户的权限。

chmod 命令还支持三种操作符来修改权限:

  • +(添加):为指定的用户类别添加特定的权限。
  • -(删除):从指定的用户类别删除特定的权限。
  • =(赋予):为指定的用户类别赋予确切的权限,替换当前的权限设置。

权限使用字母 r(读)、w(写)和 x(执行)来表示:

  • r 表示可读权限。
  • w 表示可写权限。
  • x 表示可执行权限。

数字设定法

数字设定法: 在编程中设置文件或目录权限时,可以使用数字设定法,它通过三位八进制数来表示权限。

权限的二进制表示

  • 每个权限位(读、写、执行)用一个二进制数字表示,其中 0 表示没有权限,1 表示有权限。
  • 例如,rwx(读、写、执行)的二进制表示为 111

八进制转换:每三位二进制数转换为一个八进制数,因此文件的完整权限可以用三位八进制数表示。

记住一些常见的默认权限是很有用的。例如:
– 新建目录的默认权限通常是 775(八进制),二进制表示为 111111101
– 新建普通文件的默认权限通常是 664(八进制),二进制表示为 110100100

奇偶数规则:一个重要的结论是,如果权限的八进制数中任何一个数字是奇数,则对应用户类别具有执行权限;如果是偶数,则没有执行权限。

chmod 命令也可以使用数字设定法来改变权限,格式为 chmod <数字> <文件或目录>

在编程语言中使用数字设定法时,通常需要在八进制数前加上 0 作为前缀,以表示这是一个八进制数。

which

which 指令的用途which 指令用于查询系统中可执行程序的路径名。当提供了一个命令或已知的可执行程序作为参数时,which 会显示该程序的完整路径。

如何查找可执行程序

  1. 解释器的查找过程: Shell 解释器(如 bash)在执行命令时,会根据环境变量 PATH 指定的搜索路径来查找对应的可执行程序。PATH 环境变量包含了一系列的目录路径,Shell 解释器会按照这些路径的顺序进行搜索。
  2. env 指令: 使用 env 指令可以查看当前会话的所有环境变量,包括 PATHPATH 变量定义了 Shell 解释器搜索可执行程序的顺序。
  3. 当前目录的执行: 如果需要执行当前工作目录下的可执行程序,通常需要使用 ./ 前缀。这是因为如果没有指定路径,Shell 解释器会在 PATH 环境变量定义的路径中搜索命令。
  4. 内置命令: 有些命令是 Shell 解释器的内置命令,它们是解释器的一部分,不需要外部的可执行文件。例如,cd 就是一个内置命令。由于这些命令不是外部程序,which 指令无法查询到它们的路径。

示例

  • 要查找 ls 命令的可执行文件路径,可以使用:which ls
  • 要查看当前会话的环境变量,可以使用:env

命令的组合

进程间通信(IPC): 由于进程之间的隔离特性,它们通常不能直接交换数据。然而,在需要进程间数据交互的场景下,可以采用多种通信机制。

使用管道进行 IPC

  1. 管道的概念:管道是一种特殊的文件类型,它允许两个进程通过一个缓冲区进行数据交换。
  2. 系统调用:使用管道时,需要进行系统调用,这会触发内核在内存中分配一段连续的内存空间,作为管道的缓冲区。
  3. 数据交换:数据可以通过管道的一端写入,然后从另一端读取出来,类似于生活中的管道。写入端对应于发送数据的进程,读取端对应于接收数据的进程。
  4. 实现 IPC:如果管道的两端分别连接到两个进程,就可以实现这两个进程之间的数据通信。

管道的类型

  • 匿名管道:不需要命名,通常用于父子进程或兄弟进程之间的通信。
  • 命名管道(FIFO):具有文件系统中的名称,可以用于不相关的进程之间的通信。

命令组合与管道: 命令组合 cmd1 | cmd2 利用管道实现了两个进程间的通信。管道 | 允许 cmd1 的标准输出(stdout)直接成为 cmd2 的标准输入(stdin)。

工作原理

  1. 重定向cmd1 将数据输出到它的标准输出,而 cmd1|cmd2 结构将这个标准输出重定向到管道中。
  2. 进程间通信cmd2 从它的标准输入读取数据,而这个标准输入现在连接到了管道。
  3. 数据流:数据从 cmd1 输出流向管道,然后流向 cmd2 的输入,实现了两个独立命令的数据流连接。

注意事项

  1. 命令选择cmd1 必须是能够产生输出的命令,如 historyheadtaillsgrepfindcatwc 等。
  2. 输入要求cmd2 必须是能够处理来自标准输入的数据流的命令,例如 headtailcatwcgrep 等。

命令组合 cmd1 | xargs cmd2: 这种组合方式允许将 cmd1 的输出作为参数传递给 cmd2xargs 命令将输入数据(来自 cmd1 的输出)转换为命令行参数,并执行 cmd2

工作原理

  • cmd1 产生输出,通常是一个列表或流。
  • xargs 读取 cmd1 的输出,并将输出逐行或根据空白字符分割成参数。
  • cmd2 接收 xargs 提供的参数,并执行。

使用场景

  1. 搜索包含特定函数的源文件
    find . -name "*.C" | xargs grep -n "main"
    

    这个命令组合搜索当前目录及子目录下所有以 .C 结尾的文件,并查找包含 main 函数的行。

  2. 删除特定条件的文件

  • 删除家目录下所有大于 100MB 的普通文件:

    find ~ -type f -size +100M | xargs rm
    
  • 删除当前目录下所有以 .c 结尾的文件:
    find . -type f -name "*.c" | xargs rm
    

注意

  • xargs 可以处理来自标准输入的输出,将其转换为命令行参数。
  • 命令组合提供了一种灵活的方式来执行复杂的任务,如搜索、过滤和删除文件。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇