介绍
在本实验中,你将学习在 Linux 命令行环境中管理文件和目录的基础技能。你将通过实践获得使用 mkdir 和 rm 创建及删除复杂目录结构的经验,并学习使用 cp 和 mv 复制及移动文件和目录。
此外,本实验还提供了对文件链接(Linking)的深入探索。你将使用 ln 命令创建符号链接(软链接)和硬链接,分析底层的索引节点(inode)概念,并观察当源文件被修改时,每种链接类型所表现出的不同行为。这将帮助你更深入地理解 Linux 文件系统是如何组织和引用数据的。
使用 mkdir、rmdir 和 rm 创建与删除目录结构
在这一步中,你将学习如何创建和删除目录。将文件组织到目录的分层结构中是 Linux 中的一项基本任务。我们将使用 mkdir 命令创建目录,使用 rmdir 删除空目录,以及使用 rm 删除目录及其所有内容。所有命令都将在你的默认目录 ~/project 中执行。
首先,让我们创建一个简单的目录。mkdir 命令代表「make directory」(创建目录)。
在终端中执行以下命令来创建一个名为 cars 的目录:
mkdir cars
要验证目录是否已创建,可以使用 ls -ld 命令。-l 选项提供长列表格式,-d 选项仅列出目录条目本身,而不是其内容。
ls -ld cars
你应该会看到类似下面的输出,确认 cars 目录已创建。权限字符串开头的 d 表示这是一个目录。
drwxr-xr-x 2 labex labex 4096 May 20 10:30 cars
现在,让我们删除这个目录。rmdir 命令用于删除「空」目录。
rmdir cars
再次运行 ls -ld 命令验证其是否已被删除。
ls -ld cars
这一次,你会收到一条错误消息,因为该目录已不存在。这证明 rmdir 执行成功。
ls: cannot access 'cars': No such file or directory
rmdir 命令仅适用于空目录。如果我们有一个嵌套的目录结构该怎么办?让我们尝试创建一个目录结构 pastry/pies/cakes。为了根据需要创建父目录,我们必须在 mkdir 中使用 -p(parents)选项。
执行以下命令:
mkdir -p pastry/pies/cakes
要查看刚刚创建的整个目录结构,请使用带有 -l(长格式)和 -R(递归)选项的 ls 命令。
ls -lR pastry
输出将显示 pastry 目录及其子目录 pies 和 cakes。
pastry:
total 4
drwxr-xr-x 3 labex labex 4096 May 20 10:35 pies
pastry/pies:
total 4
drwxr-xr-x 2 labex labex 4096 May 20 10:35 cakes
pastry/pies/cakes:
total 0
现在,让我们尝试使用 rmdir 删除 pastry 目录。
rmdir pastry
为什么这个命令失败了?终端会显示一条错误消息:
rmdir: failed to remove 'pastry': Directory not empty
这是因为 rmdir 只能删除空目录,而 pastry 包含了 pies 子目录。
要删除一个目录及其所有内容(包括子目录和文件),必须使用带有 -r(递归)选项的 rm 命令。请务必小心使用此命令,因为它会永久删除数据。
rm -r pastry
如果执行成功,该命令不会产生任何输出。你可以通过再次运行 ls -ld pastry 来验证 pastry 目录是否已被完全删除,这应该会导致「No such file or directory」错误。
ls -ld pastry
使用 vi 和 ln -s 创建文件和符号链接
在这一步中,你将使用 vi 文本编辑器创建一个文件,然后为其创建一个符号链接。符号链接(Symbolic link),也称为软链接(Soft link),是一种特殊类型的文件,它指向另一个文件或目录。它类似于其他操作系统中的「快捷方式」。
首先,让我们使用 vi 创建一个名为 filea 的简单文本文件。vi 是一个功能强大的屏幕文本编辑器。它有两种主要模式:命令模式(Command mode)和插入模式(Insert mode)。启动时处于命令模式,此时按键被解释为命令。要输入文本,必须进入插入模式。
- 在终端中(路径应为
~/project),启动vi以创建文件filea:
vi filea
- 终端现在将显示
vi编辑器界面。要开始输入,需要切换到插入模式。按一次i键。你可能会在屏幕底部看到-- INSERT --字样。 - 现在,输入以下文本:
This is filea.
- 要保存文件并退出
vi,必须先按Esc键返回命令模式。然后,输入ZZ(按住 Shift 并连按两次 Z)。此命令将保存文件并退出编辑器。
现在回到命令提示符,让我们验证文件是否已创建且内容正确。
首先,列出文件:
ls filea
输出应仅为文件名:
filea
接下来,使用 cat 命令显示其内容:
cat filea
输出应与你输入的文本一致:
This is filea.
现在,让我们创建一个符号链接。我们将创建一个名为 fileb 的链接,指向我们的原始文件 filea。命令格式为 ln -s <源文件> <目标链接>。
ln -s filea fileb
要测试结果,请使用 ls -il 命令。-i 选项显示索引节点(inode)编号,它是文件系统上文件或目录的唯一标识符。
ls -il file[ab]
仔细检查输出。
131075 -rw-r--r-- 1 labex labex 14 May 20 10:40 filea
131076 lrwxrwxrwx 1 labex labex 5 May 20 10:41 fileb -> filea
请注意几个关键点:
- 文件类型:
filea的权限字符串以-开头,表示一个普通文件。fileb的字符串以l开头,表示一个符号链接。 - 链接指针:输出清晰地显示了
fileb -> filea。 - Inode 编号:查看第一列。
filea和fileb的 inode 编号是不同的。为什么?因为符号链接是一个独立的文件,它只是存储了目标文件的路径。它本身不是那个文件,因此拥有自己唯一的 inode。
最后,让我们看看是否可以通过链接读取内容。
cat fileb
输出是 filea 的内容:
This is filea.
这是预期行为。当你对符号链接执行 cat 之类的操作时,系统会自动跟随链接找到源文件并对其执行操作。
使用 ln 和 Inode 创建并分析硬链接
在这一步中,你将创建一个硬链接(Hard link),并了解它与之前创建的符号链接有何不同。符号链接是指向文件名的指针,而硬链接则是文件本身的另一个名称。两个名称都直接指向磁盘上的同一块数据,这块数据由一个称为 inode 的唯一编号标识。
我们将继续在 ~/project 目录中使用上一步中的文件 filea 和 fileb。
首先,让我们创建一个名为 filec 的硬链接,使其指向与 filea 相同的 inode。为此,我们使用不带 -s 选项的 ln 命令。
ln filea filec
现在,让我们查看所有三个文件的内容:原始文件 filea、符号链接 fileb 以及新的硬链接 filec。
cat filea
cat fileb
cat filec
你会看到相同的内容被打印了三次,这是预料之中的。
This is filea.
This is filea.
This is filea.
当我们检查文件属性时,真正的区别就显现出来了。再次使用 ls -il 命令查看所有三个文件的 inode 编号和其他详细信息。
ls -il file[a-c]
输出将类似于这样。请密切注意第一列和第二列。
131075 -rw-r--r-- 2 labex labex 14 May 20 10:40 filea
131076 lrwxrwxrwx 1 labex labex 5 May 20 10:41 fileb -> filea
131075 -rw-r--r-- 2 labex labex 14 May 20 10:40 filec
让我们分析一下这个输出:
- Inode 编号(第 1 列):注意
filea和filec具有完全相同的 inode 编号(例如131075)。这是硬链接的定义特征。它们不是独立的文件;它们是指向磁盘上相同文件数据的两个不同名称。而符号链接fileb拥有自己唯一的 inode。 - 链接计数(第 2 列):查看
filea和filec的数字。它现在是2。这个数字是硬链接计数,它跟踪有多少个名称(硬链接)指向这个单一的 inode。当你创建filec时,该 inode 的链接计数从 1 增加到了 2。 - 文件类型(权限字符串的第 1 位):注意
filec被列为普通文件(其权限以-开头),就像filea一样。它不是像fileb(以l开头)那样的特殊链接类型。
观察修改源文件后的链接行为
在这一步中,你将观察当原始源文件被删除并重新创建时,符号链接和硬链接在行为上的关键差异。这将巩固你对每种链接工作原理的理解。我们将继续在 ~/project 目录中使用 filea、fileb 和 filec。
首先,让我们删除原始文件 filea。
rm filea
现在,让我们检查这三个文件的状态。使用 ls -l 命令。由于 filea 已不存在,你可能会看到关于它的错误,这是正常的。
ls -l file[a-c]
输出将非常有启发性:
ls: cannot access 'filea': No such file or directory
lrwxrwxrwx 1 labex labex 5 May 20 10:41 fileb -> filea
-rw-r--r-- 1 labex labex 14 May 20 10:40 filec
- **符号链接
fileb**:链接现在「断开了」。它仍然指向名称filea,但该名称不再对应任何现有文件。在许多终端中,文件名fileb会显示为红色以指示这种断开状态。如果你尝试cat fileb,将会报错。 - **硬链接
filec**:文件filec完全不受影响。它的链接计数(第二列)只是从 2 减少到了 1,但文件及其数据依然完好无损。这是因为删除filea只是删除了指向该 inode 的其中一个名称;直到链接计数降为零,数据才会被删除。你可以通过查看其内容来证明这一点:
cat filec
输出仍然是原始内容:
This is filea.
现在,让我们重新创建 filea,但使用不同的内容。使用 vi 创建一个名为 filea 的新文件。
- 启动
vi:vi filea - 按
i进入插入模式。 - 输入新内容:
This is the new filea. - 按
Esc返回命令模式,然后输入ZZ保存并退出。
有了新的 filea 后,让我们再次使用 ls -il 检查这三个文件。
ls -il file[a-c]
输出将显示一种新情况:
131080 -rw-r--r-- 1 labex labex 20 May 20 11:05 filea
131076 lrwxrwxrwx 1 labex labex 5 May 20 10:41 fileb -> filea
131075 -rw-r--r-- 1 labex labex 14 May 20 10:40 filec
- 新的
filea:一个新的filea文件存在了,但请注意它的 inode 编号(例如131080)与filec的 inode(例如131075)是不同的。这是一个全新的文件,只是恰好与旧文件同名。 - **符号链接
fileb**:链接不再断开!它自动指向了名为filea的新文件。 - **硬链接
filec**:filec保持不变。它仍然指向原始的 inode 并包含原始数据。
最后,让我们检查所有三个文件的内容以查看结果。
cat filea
cat fileb
cat filec
输出清晰地展示了区别:
This is the new filea.
This is the new filea.
This is filea.
符号链接 fileb 跟随名称找到了新文件,而硬链接 filec 则维持了与原始数据的连接。
使用 cp 和 mv 复制与移动文件
在最后一步中,你将学习使用 cp(复制)和 mv(移动)命令,它们是管理文件的核心工具。cp 命令创建文件或目录的副本,而 mv 命令则用于重命名文件/目录或将其移动到不同位置。
首先,让我们清理之前步骤中的文件,以获得一个干净的工作空间。所有命令都将在 ~/project 目录中运行。
rm filea fileb filec
使用 cp 复制文件
cp 命令会创建一个新的、独立的副本。新文件将拥有自己的 inode。
- 首先,使用
touch命令创建一个简单的文件。如果文件不存在,touch会创建一个空文件。
touch source_file
- 现在,查看其属性,注意 inode 编号(第一列)。
ls -i source_file
输出将显示该文件的唯一 inode 编号。
131081 source_file
- 接下来,将
source_file复制到一个名为copied_file的新文件。
cp source_file copied_file
- 现在,列出这两个文件的属性。
ls -i source_file copied_file
你会看到它们是两个独立的文件,具有不同的 inode 编号。
131082 copied_file
131081 source_file
使用 mv 移动和重命名文件
mv 命令非常多才。如果目标是同一目录下的新文件名,它会重命名文件。如果目标是一个目录,它会将文件移动到该目录中。当在同一个文件系统内重命名或移动文件时,inode 编号不会改变;该命令只是更新了文件的名称或位置指针。
- 让我们将
source_file重命名为renamed_file。
mv source_file renamed_file
- 检查新命名文件的 inode。
ls -i renamed_file
你会注意到 inode 编号(例如 131081)与原始的 source_file 相同。文件本身没有改变,改变的只是它的名字。
131081 renamed_file
- 现在,让我们移动这个文件。首先,创建一个目标目录。
mkdir move_destination
- 将
renamed_file移动到move_destination目录中。
mv renamed_file move_destination/
- 验证文件现在是否在目录内,并再次检查其 inode。
ls -i move_destination/renamed_file
inode 编号保持不变,确认文件是被移动了,而不是被复制。
131081 move_destination/renamed_file
处理覆盖操作
默认情况下,许多系统将 cp 别名为 cp -i,以防止你意外覆盖现有文件。-i 代表「interactive」(交互式)。
- 让我们尝试将
copied_file复制并覆盖move_destination目录内的文件。
cp -i copied_file move_destination/renamed_file
- 由于
-i别名的存在,系统会提示你确认。
cp: overwrite 'move_destination/renamed_file'?
输入 y 并按回车键确认覆盖。如果你想取消,可以输入 n。
总结
在本实验中,你学习了在 Linux 环境中管理文件和目录的基本命令。你练习了使用 mkdir 创建目录结构(包括用于创建父目录的 -p 选项),并学习了使用 rmdir 删除空目录以及使用 rm 删除非空目录。你还使用 vi 编辑器创建了文件,并初步了解了文件链接的概念。
实验的核心在于创建和分析两种类型的链接:使用 ln -s 创建的符号链接(软链接)和使用 ln 创建的硬链接。通过检查 inode 并观察当源文件被修改或删除时每种链接的表现,你掌握了它们之间的关键区别。最后,你使用 cp 命令创建了文件的独立副本,并使用 mv 命令移动或重命名了文件和目录,完成了对基本文件管理操作的全面学习。



