Skip to content

文件管理

运维工作里最常见的操作基本都在文件层面:部署新版本要拷贝文件、排查报错要翻日志、磁盘告警要找大文件清理、改配置前要备份原文件。这些操作本身都不复杂,但边界情况特别容易踩坑——删了文件空间没释放、变量为空导致 rm -rf / 把系统删了、软链接断链服务静默出错、文件类型和扩展名对不上导致打不开。

日常运维大量时间都花在跟文件打交道:看内容、找位置、确认类型和权限、清理空间。

一、文件类型

ls -l 输出第一列的第一个字符,标记的就是文件类型。Linux 的设计哲学是"一切皆文件"——不光文本是文件,目录、设备、管道、socket 全都以文件的形式存在。

bash
ls -l /etc/passwd /etc /dev/null
标记类型是什么
-普通文件文本、二进制、压缩包等等
d目录目录本身也是个文件,记录包含的文件名和 inode
l软链接指向另一个路径的"快捷方式"
c字符设备按字符流读写的设备,比如终端、串口
b块设备按数据块读写的设备,比如硬盘
ssocket进程间通信用的套接字文件
p管道命名管道(FIFO),用于进程间数据传输

光看后缀名判断文件类型经常翻车,正确做法是用 file 命令看真实内容:

bash
file /bin/ls           # ELF 可执行文件
file /etc/passwd        # ASCII 文本
file app.log            # 可能是文本、压缩包,或者编码不对的二进制

排查"日志打不开"的时候,先 file 看一眼实际类型。经常遇到这种情况:文件名明明是 .log,用 cat 打开一堆乱码——其实它是 logrotate 轮转之后 gzip 压缩过的旧日志,得用 zcat 或者 gunzip 解开看。

二、查看目录内容

bash
ls -l      # 长格式,显示权限、大小、修改时间
ls -la     # 加 -a 显示隐藏文件(以 . 开头的文件)
ls -lh     # 大小以人类可读格式显示(K、M、G)
ls -ltr    # 按修改时间排序,最新在最后

看日志目录的时候 ls -lhtr /var/log 这个组合特别顺手——-t 按时间排序、-r 反序(最新的放最后),这样最新产生的日志文件在最下面,一眼就能看到,不用往上翻一长串历史文件。

三、文件内容查看

小文件直接 cat 一次全输出:

bash
cat /etc/hosts

大文件用 less,可以前后翻页、搜索,不会像 cat 那样一次性刷屏:

bash
less /var/log/messages

less 里几个高频操作:

干什么
/keyword向下搜索
?keyword向上搜索
n跳到下一个匹配
N跳到上一个匹配
g跳到文件开头
G跳到文件末尾
q退出

看文件头和尾:

bash
head -n 20 app.log        # 前 20 行
tail -n 50 app.log        # 最后 50 行
tail -f app.log           # 持续跟踪新增内容(实时看日志)

tail -f 是排查问题时的神器,适合流量不大的日志实时监控。但如果日志刷得飞快(比如高 QPS 的访问日志),直接 tail -f 眼睛根本跟不上,得配合 grep 过滤关键字,或者按时间段把日志切出来再看。

四、复制移动删除

bash
cp source.txt target.txt              # 复制文件
cp -a /etc/nginx /backup/nginx        # 递归复制,保留权限、时间戳、软链接
mv old.txt new.txt                    # 移动或重命名
rm file.txt                           # 删除文件
rm -r dir                             # 递归删除目录

这里要强调一下 cp -a:备份配置目录时用 cp -acp -r 靠谱得多-a 会保留属主、权限模式、修改时间、软链接,而 cp -r 默认会丢掉这些。等你恢复配置的时候发现权限全乱了,服务起不来,就知道为什么该用 -a 了。

删除操作没有回收站,rm 完基本找不回来。删之前确认两件事——当前路径对不对、目标对不对:

bash
pwd
ls -ld target-dir

变量拼接路径的删除命令是高危操作。如果变量没赋值(为空),rm -rf /$UNDEFINED_VAR/ 展开就是 rm -rf /,整个系统直接没了——这种事故真实发生过。遇到变量拼路径的情况,先 echo 把展开结果打印出来确认,再执行 rm

五、文件查找

find 是按条件搜索文件的主力工具,支持文件名、大小、时间等多种过滤:

bash
find /etc -name "*.conf"              # 按文件名查找
find /var -type f -size +100M         # 查找大于 100M 的文件
find /var/log -type f -mtime +7       # 修改时间在 7 天前的文件
find /var/log -type f -mmin -30       # 30 分钟内修改过的文件

排查磁盘空间告警,套路基本固定:先用 du 看哪个目录在占空间,再用 find 定位具体大文件:

bash
du -sh /*                  # 看根目录下各目录的占用
du -sh /var/*              # 逐层深入,定位到 /var 下哪个子目录
find /var -type f -size +1G -ls    # 直接列出大于 1G 的文件

找到大文件之后,先确认这个文件还在不在被进程写入,再决定怎么清理。如果某个进程还持有这个文件的句柄(比如 Nginx 还在往 access.log 写),直接 rm 删掉,磁盘空间不会立即释放——文件从目录里消失了,但 inode 还在,因为进程还占着。这时候要么重启那个进程,要么用 truncate 把文件清空而不是删掉。

六、软链接和硬链接

软链接(符号链接)接近 Windows 快捷方式的概念——它是一个特殊文件,里面记录的是另一个文件的路径。目标文件不存在时,软链接就成了"断链",访问会报 No such file。

bash
ln -s /opt/app/releases/v1.2.3 /opt/app/current
ls -l /opt/app/current     # 输出里会显示 -> 指向的路径

软链接最典型的用法是版本切换。发布新版本时,把 current 指向新版本目录,要回滚就指回旧版本目录,应用代码一直读 /opt/app/current 这个路径,完全感知不到背后换了版本:

bash
ln -sfn /opt/app/releases/v1.2.4 /opt/app/current

这几个参数的意思:-s 创建软链接、-f 强制覆盖已有链接、-n 关键——它确保当 current 已经是个指向目录的链接时,ln 是替换这个链接本身,而不是钻进目录内部操作。没加 -n 是个经典坑。

硬链接就不一样了,它和目标文件指向同一个 inode(磁盘上存文件元数据和数据位置的结构)。同一个 inode 可以有多个文件名,删掉其中一个,只要还有别的文件名指向这个 inode,数据就还在。

bash
ln app.log app.log.link
ls -li app.log app.log.link     # 第一列 inode 号相同

硬链接运维里很少手动建,但它背后的原理跟一个常见问题直接相关:日志文件被 rm 删了,磁盘空间却没释放。原因就是进程还持有这个文件的文件描述符,inode 的引用计数没归零,空间没真正释放。lsof | grep deleted 能看到这种情况——列出哪些"已删除"的文件还被进程占着。

七、文件时间戳

每个文件其实有三个时间,不是一个。stat 命令能一次看全:

bash
stat app.log
时间含义什么时候变
Access(atime)最后访问时间读取文件内容时更新
Modify(mtime)最后修改时间修改文件内容时更新
Change(ctime)最后状态变更时间改内容、改权限、改属主等元数据时都更新

排查"配置改了为什么没生效"的时候,statls -l 更有用——它能同时看到三个时间,还能看到 inode 号。有时候你以为改的是 A 文件,服务读的其实是另一个路径下的同名文件,或者是个软链接指向了别处。通过 inode 号对比,能确认"我改的这个文件"和"服务实际加载的那个文件"是不是同一个。