04 - 文件与目录管理
文件与目录管理是 Linux 命令行最核心的基本功。从查看文件到复制移动,从搜索查找到分析类型,这些操作将占据你日常使用的绝大部分时间。本章系统性地覆盖所有基础命令及其组合用法。
4.1 路径的概念
在深入命令之前,必须先理解 Linux 路径系统。
4.1.1 绝对路径 vs 相对路径
| 类型 | 含义 | 示例 |
|---|---|---|
| 绝对路径 | 从 /(根目录)开始的完整路径 | /home/alice/Documents/report.txt |
| 相对路径 | 从当前工作目录开始的路径 | Documents/report.txt |
pwd # 查看当前工作目录(Print Working Directory)
# 输出: /home/alice
# 以下两条命令等价(假设当前在 /home/alice)
cat /home/alice/Documents/report.txt # 绝对路径
cat Documents/report.txt # 相对路径4.1.2 特殊目录符号
| 符号 | 含义 |
|---|---|
. | 当前目录 |
.. | 上级目录(父目录) |
~ | 当前用户的主目录(等价于 $HOME) |
~username | 指定用户的主目录 |
- | 上一次所在的工作目录(cd - 专用) |
cd .. # 返回上级目录
cd ../.. # 返回上两级
cd ~ # 回到主目录
cd - # 回到上一次所在目录
ls . # 列出当前目录(与 ls 等价)
cp ../file.txt . # 将上级目录的文件复制到当前目录4.2 基础浏览命令
4.2.1 ls — 列出目录内容
ls # 列出当前目录(简洁模式)
ls -l # 详细列表(权限、大小、时间)
ls -a # 显示隐藏文件(以 . 开头)
ls -la # 详细列表 + 隐藏文件(最常用组合)
ls -lh # 详细列表 + 人类可读的文件大小(K/M/G)
ls -lt # 按修改时间排序(最新的在前)
ls -ltr # 按修改时间反向排序(最旧的在最前)
ls -R # 递归列出子目录
ls -S # 按文件大小排序
ls -i # 显示 inode 号
ls -d */ # 只列出目录(不列出文件)# 理解 ls -l 输出的每一列
$ ls -l
# -rw-r--r-- 1 alice users 4096 Mar 15 10:30 report.txt
# └─┬──────┘ │ └─┬─┘ └─┬─┘ └─┬─┘ └──────┬─────┘ └──┬─────┘
# 权限 链接数 所有者 所属组 大小 修改时间 文件名4.2.1b 文件类型标识符
ls -l 输出的第一个字符表示文件类型,这是 Linux “一切皆文件” 的体现:
| 符号 | 类型 | 说明 | 常见位置 |
|---|---|---|---|
- | 普通文件 | 文本、二进制、图片等 | 到处都是 |
d | 目录 | 文件夹 | /home, /tmp |
l | 符号链接 | 指向另一个文件的快捷方式 | /usr/bin/python3 -> python3.11 |
c | 字符设备 | 按字符读写的设备 | /dev/tty, /dev/null |
b | 块设备 | 按块读写的设备(硬盘等) | /dev/sda, /dev/nvme0n1 |
p | 命名管道 | 进程间通信 (FIFO) | /run/initctl |
s | 套接字 | 网络/进程间通信端点 | /run/docker.sock, /var/run/mysqld/mysqld.sock |
# 实际观察各种文件类型
ls -l /dev/sda # brw-rw---- 块设备
ls -l /dev/null # crw-rw-rw- 字符设备
ls -l /usr/bin/python3 # lrwxrwxrwx 符号链接
ls -l /tmp # drwxrwxrwt 目录
ls -l /run/docker.sock # srw-rw---- 套接字
# 快速统计目录下各类文件数量
ls -l | awk '{print $1}' | sort | uniq -c | sort -rn
# 输出示例:
# 15 -rw-r--r-- (普通文件)
# 8 drwxr-xr-x (目录)
# 2 lrwxrwxrwx (符号链接)目录权限的特殊含义:
r(读):可以ls列出目录内容w(写):可以在目录下创建/删除文件(需要x权限配合)x(执行):可以cd进入目录,或访问目录下的文件元数据
# 目录权限示例
drwxr-xr-x # 755 — 能进目录、能看内容、不能改
drwx------ # 700 — 只有所有者能进(私有目录)
drwxrwxrwx # 777 — 所有人可读写执行(危险!)
drwxrwxrwt # 1777 + Sticky — 所有人可写,但只能删自己的(/tmp)4.2.2 cd — 切换目录
cd /etc # 切换到 /etc
cd # 无参数 = 回到主目录
cd ~/Downloads # 切换到主目录下的 Downloads
cd "$HOME/.config" # 使用环境变量4.2.3 pwd — 显示当前工作目录
pwd # 显示逻辑路径,如 /home/alice
pwd -P # 显示物理路径(解析符号链接后的真实路径)4.3 目录管理
4.3.1 mkdir — 创建目录
mkdir project # 创建单个目录
mkdir -p a/b/c/d # 递归创建父目录(-p = parents)
mkdir -m 755 shared # 创建并指定权限(不用默认 umask)
mkdir dir1 dir2 dir3 # 同时创建多个目录
mkdir -p project/{src,docs,tests,bin} # 花括号展开,批量创建4.3.2 rmdir — 删除空目录
rmdir empty_dir # 只能删除空目录
rmdir -p a/b/c # 递归删除空的子目录链
# 实际上很多人直接用 rm -r 代替4.4 文件操作
4.4.1 touch — 创建空文件 / 更新时间戳
touch newfile.txt # 创建空文件(如果不存在)
touch existing.txt # 更新文件的修改时间到"现在"
touch -t 202512312359 file.txt # 设置指定的时间戳
touch -a file.txt # 只更新访问时间(access time)
touch -m file.txt # 只更新修改时间(modification time)4.4.2 cp — 复制
cp source.txt dest.txt # 复制文件
cp -i source.txt dest.txt # 覆盖前询问(-i = interactive)
cp -r dir1/ dir2/ # 递归复制目录(-r = recursive)
cp -a dir1/ dir2/ # 归档模式复制(保留权限、时间、符号链接等)
cp -v source.txt dest.txt # 显示复制过程(-v = verbose)
cp -u source.txt dest.txt # 仅当源文件更新时才覆盖(-u = update)
cp -p source.txt dest.txt # 保留权限和时间戳
cp file1 file2 file3 dest_dir/ # 复制多个文件到同一目录4.4.3 mv — 移动 / 重命名
mv oldname.txt newname.txt # 重命名文件
mv file.txt /path/to/dest/ # 移动文件
mv -i source.txt dest.txt # 覆盖前询问
mv -n source.txt dest.txt # 不覆盖已有文件
mv *.log archive/ # 移动所有 .log 文件4.4.4 rm — 删除
rm file.txt # 删除文件
rm -i file.txt # 删除前确认
rm -f file.txt # 强制删除(不提示,不报错如果不存在)
rm -r dir/ # 递归删除目录及所有内容
rm -rf dir/ # 强制递归删除——危险命令
rm -- -file.txt # 删除以 - 开头的文件 实际上现在linux操作系统支持**选取
rm -rf /是著名的”自杀命令”——会尝试删除系统所有文件。现代系统通常有保护(--preserve-root),但仍需极度谨慎。
4.4.5 安全删除建议
# 使用 trash-cli 代替 rm,文件可回收
# 使用你的包管理器安装:trash-cli
trash-put file.txt # 删除(移入回收站)
trash-list # 查看回收站
trash-restore # 交互式恢复
trash-empty # 清空回收站4.5 文件信息查看
4.5.1 file — 判断文件类型
Linux 不靠扩展名判断文件类型,file 命令通过读取文件头部魔数(magic number)来识别:
file document.pdf
# 输出: document.pdf: PDF document, version 1.4
file script.sh
# 输出: script.sh: Bourne-Again shell script, ASCII text executable
file /bin/ls
# 输出: /bin/ls: ELF 64-bit LSB pie executable, x86-64, ...
file image.png
# 输出: image.png: PNG image data, 1920 x 1080, 8-bit/color RGBA
file archive.tar.gz
# 输出: archive.tar.gz: gzip compressed data, from Unix
file -i document.pdf # 显示 MIME 类型
# 输出: document.pdf: application/pdf; charset=binary4.5.2 stat — 查看文件详细信息
stat file.txt
# 输出:
# File: file.txt
# Size: 4096 Blocks: 8 IO Block: 4096 regular file
# Device: 259,2 Inode: 1234567 Links: 1
# Access: (0644/-rw-r--r--) Uid: (1000/ alice) Gid: (1000/ users)
# Access: 2024-03-15 10:30:00.000000000 +0800
# Modify: 2024-03-14 15:20:00.000000000 +0800
# Change: 2024-03-14 15:20:00.000000000 +0800
# Birth: 2024-01-01 00:00:00.000000000 +0800三个时间戳的含义:
| 时间 | 含义 | 触发条件 |
|---|---|---|
| Access (atime) | 最后访问时间 | 读取文件内容或执行 |
| Modify (mtime) | 最后修改时间 | 文件内容被修改 |
| Change (ctime) | 最后状态变更时间 | 权限、所有者、链接数等元数据变更 |
4.5.3 type — 查看命令类型
type ls
# 输出: ls is aliased to `ls --color=auto' (如果是别名)
# 或: ls is /usr/bin/ls (如果是外部命令)
type cd
# 输出: cd is a shell builtin (内建命令)
type -a echo # 列出所有可能(别名、内建、外部)
type -t ls # 只显示类型(alias/keyword/builtin/file)4.5.4 which / whereis — 查找命令位置
which python # 在 PATH 中查找可执行文件
which -a python # 显示所有匹配(所有路径)
whereis python # 查找二进制、源码和 man 手册页位置4.6 文件搜索
4.6.1 find — 强大的文件搜索
find 是 Linux 最强大也最复杂的文件搜索工具。基本语法:
find [搜索路径] [匹配条件] [动作]按文件名搜索:
find /home -name "*.txt" # 精确匹配(区分大小写)
find /home -iname "*.TXT" # 忽略大小写
find /home -name "*.txt" -o -name "*.md" # 或逻辑(-o = OR)按类型搜索:
find / -type f -name "*.conf" # 只找普通文件
find / -type d -name "config" # 只找目录
find / -type l -name "*.so" # 只找符号链接按大小搜索:
find /var/log -size +100M # 大于 100MB 的文件
find /var/log -size -10k # 小于 10KB 的文件
find / -size +1G -size -5G # 1GB 到 5GB 之间
find /tmp -empty # 空文件或空目录按时间搜索:
find /home -mtime -1 # 最近 1 天内修改的文件
find /home -mtime +7 # 7 天前修改的文件
find /home -mmin -30 # 最近 30 分钟内修改的文件
find /home -atime -1 # 最近 1 天内访问过的文件
find /home -newer reference.txt # 比 reference.txt 更新的文件按权限搜索:
find / -perm 777 # 权限恰好为 777 的文件
find / -perm -u+s # 设置了 SUID 位的文件
find /home -user alice # 属于 alice 用户的文件
find /home -group users # 属于 users 组的文件对搜索结果执行操作:
find . -name "*.bak" -delete # 删除所有 .bak 文件 现代linux中可以先find列出再由第二次指令rm删除(上一条指令)
find . -name "*.log" -exec rm {} \; # 对每个找到的文件执行 rm
find . -name "*.txt" -exec mv {} {}.old \; # 批量重命名
find . -type d -exec chmod 755 {} \; # 修改所有目录权限
# -exec ... + 更高效(批量传递,减少进程开销)
find . -name "*.txt" -exec wc -l {} + # 统计所有 .txt 文件的行数
# 交互式确认
find . -name "*.tmp" -ok rm {} \; # 每次操作前询问(y/n)4.6.2 locate — 快速文件名搜索
locate 通过预先建立的数据库搜索,速度比 find 快很多,但结果可能不是实时的:
# 安装 mlocate(通常系统已有)
# Debian/Ubuntu: sudo apt install mlocate
# Fedora: sudo dnf install mlocate
# Arch: sudo pacman -S mlocate
sudo updatedb # 更新数据库(通常由 cron 自动运行)
locate fstab # 搜索包含 "fstab" 的文件路径
locate -i fstab # 忽略大小写
locate -c nginx # 统计匹配数量
locate -l 10 nginx # 限制显示前 10 条
locate -e nginx # 只显示实际存在的文件
locate -r '\.conf$' # 使用正则表达式(搜索 .conf 结尾)4.7 通配符与 Glob 模式
Shell 的通配符(glob)扩展对于高效文件操作至关重要。
| 模式 | 含义 | 示例 |
|---|---|---|
* | 匹配任意字符(0 个或多个) | *.txt 匹配所有 .txt 文件 |
? | 匹配任意单个字符 | file?.txt 匹配 file1.txt, fileA.txt |
[abc] | 匹配集合中任一字符 | file[123].txt 匹配 file1.txt, file2.txt, file3.txt |
[a-z] | 匹配字符范围内任一 | file[a-c].txt 匹配 fileA.txt, fileB.txt, fileC.txt |
[!abc] | 匹配不在集合中的字符 | file[!0-9].txt 排除数字 |
{a,b,c} | 花括号展开(不是严格 glob) | {src,test}/main.go → src/main.go test/main.go |
** | 递归匹配(需 globstar 选项) | **/*.go 递归匹配所有目录的 .go 文件 |
# 实用示例
ls *.log # 列出所有 .log 文件
cp /data/{2023,2024}/*.csv ./ # 复制两个年份的 CSV
rm tmp.[0-9]* # 删除 tmp.0, tmp.1, tmp.123...
ls file.??? # 匹配 file.txt, file.log, file.jpg...
# 启用递归 glob(bash 4.0+)
shopt -s globstar # 启用 **
echo **/*.md # 递归列出所有 .md 文件
shopt -u globstar # 恢复禁用4.8 路径与命令的技巧
4.8.1 dirname 和 basename
dirname /home/alice/file.txt
# 输出: /home/alice
basename /home/alice/file.txt
# 输出: file.txt
basename /home/alice/file.txt .txt
# 输出: file (去掉后缀)
# 在脚本中的经典用法
FILEPATH="/var/log/nginx/access.log"
DIR=$(dirname "$FILEPATH")
FILE=$(basename "$FILEPATH")4.8.2 realpath 和 readlink
realpath ./relative/path # 解析为绝对路径
realpath -m /nonexistent/path # 即使路径不存在也标准化
readlink -f /usr/bin/python # 递归跟随符号链接,返回最终目标4.9 实战技巧
4.9.1 批量重命名
# 将所有 .txt 改为 .md
for f in *.txt; do mv "$f" "${f%.txt}.md"; done
# 使用 rename 工具(更强大)
# 安装: 使用你的包管理器安装 perl-rename 或 rename
rename 's/\.txt$/\.md/' *.txt # Perl 风格 rename
rename 's/ /_/g' * # 将所有空格替换为下划线4.9.2 查找并删除重复文件
# 查找重复文件(按内容哈希)
find . -type f -exec md5sum {} + | sort | uniq -w32 -dD
# 查找并列出大文件(Top 10)
find / -type f -exec du -h {} + 2>/dev/null | sort -rh | head -104.9.3 快速清空文件内容
> file.log # 最快方式:重定向清空
truncate -s 0 file.log # truncate 命令
echo -n > file.log # echo 方式
true > file.log # true 重定向方式4.9.4 目录大小快速分析
du -sh * # 当前目录下每个文件/目录的大小
du -sh */ # 只统计目录
du -h --max-depth=1 /var # 只统计第一层
ncdu # 交互式磁盘使用分析器(需安装)4.10 常见陷阱
| 陷阱 | 说明 | 正确做法 |
|---|---|---|
cp dir1 dir2 未加 -r | 复制目录必须加 -r | cp -r dir1 dir2 |
| 文件名包含空格 | rm My File.txt 会尝试删除 My 和 File.txt | rm "My File.txt" 或用 \ 转义 |
rm -rf / 路径 | 根目录误删 | 永远确认路径,使用 trash-cli |
在 find 中未加引号 | find . -name *.txt 中 *.txt 会被 shell 先行展开 | find . -name "*.txt" |
忘记 -p 选项 | mkdir a/b/c 若 a 或 b 不存在则失败 | mkdir -p a/b/c |
4.11 相关链接
- 03-FHS文件系统层次标准 — 了解每个目录的用途
- 44-压缩与归档工具大全 — 打包和压缩文件
- 06-命令行基础与Shell入门 — Shell 基础与通配
- 08-用户与权限管理 — 文件权限与所有者
- 12-存储管理与磁盘操作 — 磁盘分区和挂载