文件和目录操作

LinuxBeginner
立即练习

简介

Linux 将文件组织在一棵从 /(根目录)开始的目录树中。每个文件和目录都有一个路径,用于描述它在目录树中的位置。学会读取和使用路径,几乎可以让之后的所有 Linux 任务都变得更简单。

在本实验中,你将创建一个小型工作区,同时学习日常终端操作中常用的命令。你将浏览目录、创建和编辑文件、复制和移动数据、查找文件、检查元数据和 inode、体验硬链接与符号链接,并使用 diff 比较文件和目录树。

探索 Linux 目录树

在本步骤中,你将确认当前位置,检查重要的顶层目录,并为实验的其余部分创建专用工作区。

pwd 命令表示「打印工作目录」。先运行它,确认终端启动时所在的位置:

pwd

结果应为 /home/labex/project。绝对路径以 / 开头,用于描述从文件系统根目录开始的位置。

列出文件系统的顶层目录:

ls /

你会看到 etchometmpusrvar 等标准目录。它们通常用于:

  • /etc 存储系统范围的配置。
  • /home 存储普通用户的主目录。
  • /tmp 存储临时数据。
  • /usr 包含许多已安装的程序和共享资源。
  • /var 包含日志和缓存等会变化的数据。

-d 选项告诉 ls 描述指定的目录本身,而不是列出目录内容。-l 选项选择长格式:

ls -ld /etc /home /tmp /usr /var

每行的第一个字符是 d,表示该对象是目录。其余列包含权限、所有者、大小、时间和名称。

为本实验创建工作区。-p 选项允许 mkdir 创建缺失的父目录;如果目录已经存在,也不会报错:

mkdir -p /home/labex/project/file-ops-lab

进入该目录并确认新位置:

cd /home/labex/project/file-ops-lab
pwd

最后的输出应为 /home/labex/project/file-ops-lab

使用绝对路径和相对路径浏览目录

在本步骤中,你将创建嵌套目录树,并使用绝对路径、相对路径和目录导航快捷方式在其中移动。

确保从实验工作区开始:

cd /home/labex/project/file-ops-lab

使用一条命令创建三个嵌套目录:

mkdir -p navigation/alpha/beta

这里的 navigation/alpha/beta 是相对路径,因为它不是以 / 开头的。Shell 会根据当前目录解析该路径。

使用绝对路径进入最深层的目录:

cd /home/labex/project/file-ops-lab/navigation/alpha/beta
pwd

特殊路径 .. 表示父目录。从 beta 移动到 alpha

cd ..
pwd

输出应以 /navigation/alpha 结尾。cd - 命令会返回上一个工作目录:

cd -
pwd

你应已返回 beta 目录。最后,~ 表示你的主目录。将它作为路径的开头,返回实验工作区:

cd ~/project/file-ops-lab
pwd

绝对路径可以从任何位置使用。如果你已经知道当前位置,相对路径会更短。

创建目录并写入文件

在本步骤中,你将创建目录和文件,然后学习 Shell 重定向中覆盖与追加的区别。

先进入实验工作区,同时创建两个目录:

cd /home/labex/project/file-ops-lab
mkdir documents archive

如果指定的文件不存在,touch 命令会创建一个空文件:

touch documents/empty.txt

使用长格式列出该空文件:

ls -l documents/empty.txt

文件大小应为 0 字节。接下来,> 会将命令输出重定向到文件中。它会创建文件,或替换文件原有内容:

echo "Linux file practice" > documents/notes.txt

>> 运算符会追加输出,而不会删除现有内容:

echo "Paths identify each filesystem object" >> documents/notes.txt

使用 cat 显示完整文件:

cat documents/notes.txt

你应看到两行内容,顺序与写入时一致。使用 wc -l 统计行数;-l 要求 wc 统计行数:

wc -l documents/notes.txt

第一个字段应为 2

复制、移动、重命名和删除文件

在本步骤中,你将练习文件系统对象发生变化时的四种常见操作:复制、移动、重命名和删除。

返回实验工作区:

cd /home/labex/project/file-ops-lab

cp 命令会将源对象复制到目标位置。将 notes.txt 复制到 archive,并使用新名称:

cp documents/notes.txt archive/notes-backup.txt

确认源文件和副本都存在:

ls -l documents/notes.txt archive/notes-backup.txt

创建一个临时文件,然后使用 mv 在一次操作中移动并重命名它:

echo "draft" > documents/draft.txt
mv documents/draft.txt archive/final-draft.txt

旧路径不应再存在,而新路径应存在:

ls -l archive/final-draft.txt

要复制目录及其全部内容,请使用递归选项 -r

cp -r documents archive/documents-copy
find archive/documents-copy -maxdepth 1 -type f

rm 命令会永久删除文件;终端没有回收站。创建并删除一个不再需要的文件:

touch disposable.tmp
rm disposable.tmp

列出当前目录,确认该路径已消失:

ls

输出中不应出现 disposable.tmp。使用 rm 前,务必仔细检查路径。

查看、更新和查找文件

在本步骤中,你将创建一个多行文件,检查文件的不同部分,使用追加重定向更新文件,并按名称查找它。

返回实验工作区。Here-document 会将多行内容发送给命令,直到 Shell 遇到一行只包含所选标记的内容;这里使用的标记是 EOF

cd /home/labex/project/file-ops-lab
cat > documents/journal.txt <<'EOF'
First entry: created a workspace
Second entry: practiced paths
Third entry: copied files
EOF

'EOF' 加引号可以防止 Shell 展开文档中的特殊字符。使用行号显示文件:

nl -ba documents/journal.txt

-ba 选项会为所有行编号。使用 head -n 2 查看前两行,使用 tail -n 1 查看最后一行:

head -n 2 documents/journal.txt
tail -n 1 documents/journal.txt

追加第四条记录。前面使用过 >>;它会将输出添加到末尾,不会替换已有的三行内容:

echo "Fourth entry: reviewed the results" >> documents/journal.txt

检查结果:

tail -n 2 documents/journal.txt

现在搜索工作区中的文本文件。在 find 中,. 表示当前目录,-type f 将结果限制为普通文件,-name 用于匹配文件名模式。加引号可以防止 Shell 在 find 接收到 *.txt 之前展开它:

find . -type f -name "*.txt"

输出应包含 ./documents/journal.txt,以及你创建的其他文本文件。

检查文件类型、元数据和 inode

在本步骤中,你将超越文件名本身,检查 Linux 存储的文件系统对象信息。

先进入实验工作区,然后让 file 识别两个不同的对象:

cd /home/labex/project/file-ops-lab
file documents/journal.txt /bin/ls

journal.txt 应被识别为文本文件,而 /bin/ls 应被识别为可执行程序。Linux 并不只依靠文件扩展名来识别数据。

stat 命令会显示大小、权限、所有者、时间戳和 inode 编号等元数据:

stat documents/journal.txt

inode 是文件系统中的一条记录,用于存储文件元数据并指向文件数据。文件名是目录项,它引用某个 inode。使用自定义的 stat 格式显示稳定字段:

stat -c 'name=%n type=%F size=%s inode=%i links=%h' documents/journal.txt

%i 字段表示 inode 编号,%h 表示引用该 inode 的硬链接数量。

ls-i 选项也会显示 inode 编号。创建一个用于练习元数据的文件并检查它:

echo "inode practice" > metadata-sample.txt
ls -li metadata-sample.txt

行首的数字就是 inode 编号。不同环境中的编号可能不同,因此应关注该字段代表什么,而不是记住具体数值。

使用硬链接和符号链接

在本步骤中,你将创建 Linux 中的两种链接,并观察删除原始文件名后它们各自的行为。

创建实验所需的目录和源文件:

cd /home/labex/project/file-ops-lab
mkdir links
echo "shared inode data" > links/source.txt

不带选项的 ln 命令会创建硬链接。两个名称引用同一个 inode 和文件数据:

ln links/source.txt links/hard-link.txt

-s 选项会创建符号链接,有时也称为 symlink。符号链接存储的是指向另一个文件的路径:

ln -s source.txt links/symbolic-link.txt

比较 inode 编号和链接信息:

ls -li links

source.txthard-link.txt 应具有相同的 inode 编号。符号链接拥有自己的 inode,并显示 -> source.txt

使用 readlink 显示符号链接内部存储的路径:

readlink links/symbolic-link.txt

删除原始文件名:

rm links/source.txt

硬链接仍然可以访问该 inode 及其数据:

cat links/hard-link.txt

符号链接现在指向一个不再存在的名称。尝试读取它:

cat links/symbolic-link.txt

预期会出现 No such file or directory 错误。这一结果说明:链接对象本身仍然存在,但其中存储的目标路径已经失效。这个实验表明,只要还有另一个硬链接存在,删除其中一个硬链接名称并不会删除数据;而符号链接依赖其存储的目标路径。

使用 Diff 比较文件和目录

在本步骤中,你将使用 diff 查找差异,然后同步两个小型目录树。

创建两个版本目录:

cd /home/labex/project/file-ops-lab
mkdir -p comparison/version-a comparison/version-b

创建只有一行不同的配置文件:

printf 'mode=production\nport=8080\n' > comparison/version-a/app.conf
printf 'mode=production\nport=9090\n' > comparison/version-b/app.conf

-u 选项要求 diff 以统一格式显示差异,并在每处变化附近显示上下文:

diff -u comparison/version-a/app.conf comparison/version-b/app.conf

diff 使用 - 标记第一个文件中的行,使用 + 标记第二个文件中的行。其非零退出状态表示两个文件不同;这是预期现象。

让第二个文件与第一个文件一致,然后使用 -q 进行静默相等性检查:

cp comparison/version-a/app.conf comparison/version-b/app.conf
diff -q comparison/version-a/app.conf comparison/version-b/app.conf

没有输出表示两个文件内容一致。现在只在一个目录中添加文件:

echo "release notes" > comparison/version-a/README.txt

-r 选项会递归比较目录树:

diff -r comparison/version-a comparison/version-b

输出会报告 README.txt 只存在于 version-a 中。复制该文件,然后再次比较:

cp comparison/version-a/README.txt comparison/version-b/README.txt
diff -r comparison/version-a comparison/version-b

最后一条命令应没有输出,这证明两个目录树现在包含相同的文件内容。

总结

你练习了 Linux 终端操作中使用的核心文件和目录命令。你使用绝对路径和相对路径浏览目录,创建和编辑文件,复制和移动数据,安全地删除不再需要的文件,并按文件名搜索文件。

你还检查了文件类型和元数据,了解了文件名与 inode 的关系,比较了硬链接和符号链接,并使用 diff 比较单个文件和完整目录树。这些概念将帮助你理解 Linux 文件的工作方式,而不是把命令当作彼此孤立的操作步骤。