1. 先搞明白一件事Linux目录结构不是随手拍出来的很多人第一次登上一台Linux机器敲完ls /看到一屏彩色目录名第一反应是这都啥。bin、sbin、etc、var、usr、opt、proc、sys……看着像个杂乱的老仓库实际上是几十年演进下来的一棵树每个枝杈都有明确的职责划分。我第一次管服务器的时候把应用日志直接丢在/root下面结果根分区写满机器连 ssh 都登不进去只能进机房接显示器。那次之后我才认真把目录结构从头捋了一遍。这篇东西就是那次事故复盘的产物。我会从根目录一个文件夹一个文件夹地讲清楚它归谁管、能放什么、不能放什么再往下延伸到分区规划、挂载、权限配合最后落到一个 Java Web 项目到底该部署在哪个目录这种具体问题上。适合刚接触 Linux 的运维新人也适合写了几年代码但对服务器目录仍然一头雾水的开发同学——你可以不会写 shell 脚本但你不能不知道/var被写满会带来什么。一个前提认知必须先建立Linux 里没有盘符这个概念。Windows 里 C 盘、D 盘是并列的独立空间而 Linux 只有一棵以/为根的树所有磁盘、分区、U盘、网络存储都是通过挂载这个动作挂到树上的某个枝杈。理解了这点后面关于分区和目录的所有规矩就都能串起来了。1.1 一切皆文件但文件住在不同的小区Linux 的设计哲学里有一句被说烂了的话一切皆文件。普通文本是文件硬盘是文件/dev/sda内核运行状态是文件/proc/meminfo进程编号也是文件/proc/1234。既然都是文件就得有统一的地址体系所以出现了这棵目录树。但都是文件不等于都能随便放。这棵树里每个顶层目录其实是一个功能区域类似城市里的功能分区/bin是便利店随时要用的基础工具/etc是档案室配置文件/var是垃圾中转站兼仓库会持续增长的数据/proc和/sys是监控大屏内存里实时生成不占磁盘。你把东西放错区平时可能没事一旦出事就是灾难级的——备份策略、磁盘扩容、权限模型全是按这个分区逻辑设计的。1.2 FHS那本不成文但人人都遵守的建筑规范这套目录约定有个正式名字叫FHSFilesystem Hierarchy Standard文件系统层次结构标准。它不是一个强制法律但它规定了某类文件应该放在哪个目录主流发行版都尽量遵守。你可以把它理解成装修行业的施工规范不遵守也能住人但出了问题没人帮你兜底。FHS 把目录分成几大类类别目录特点静态、可共享/usr、/opt安装后基本不变可被多台机器共享静态、机器专属/etc、/boot每台机器配置不同动态、可共享/var/mail、/var/spool/news运行中变化可共享动态、机器专属/var/log、/var/run、/var/lock运行中变化每机独立这张表看着枯燥但它的实用价值在于做备份的时候/usr、/opt这类静态目录根本不用天天备真正要天天备的是/etc、/var、业务数据目录。我见过有团队每天全盘备份 2TB 的/usr备份窗口撑到八小时纯粹是没搞清这张表的含义。1.3 不同发行版之间确实有差异FHS 是底线但各家发行版在底线之上做了自己的调整。最常见的一个变化叫usrmerge老一点的习惯里/bin、/sbin、/lib是根目录下真实的独立目录而systemd时代之后主流发行版把它们合并进了/usr原来的位置变成软链接# 在较新的发行版上你会看到这样的结果 ls -ld /bin /sbin /lib /lib64 # lrwxrwxrwx. 1 root root 7 ... /bin - usr/bin # lrwxrwxrwx. 1 root root 7 ... /sbin - usr/sbin # lrwxrwxrwx. 1 root root 7 ... /lib - usr/lib所以你现在写脚本路径写/bin/bash和/usr/bin/bash指向同一个地方没区别但在十几年前的老系统上这就不是一回事了。判断方法很简单ls -ld /bin # 输出以 l 开头 - 是软链接已合并 # 输出以 d 开头 - 是真实目录传统布局除此之外软件包管理器的差异也影响目录/etc/sysconfig/是 RPM 系RHEL、CentOS、Fedora的习惯Debian 系更倾向/etc/default/服务管理上老系统用/etc/init.d/现代系统一律/etc/systemd/system/。这些差异在写部署脚本时会真的咬你一口所以我的习惯是脚本里先探测发行版再决定读哪个配置目录。2. 根目录下每个文件夹到底是干什么的这一节是全文的核心。下面按功能相似度分组来聊每组都会说清楚这个目录归谁管、什么东西该放这儿、什么东西不该放这儿。2.1 /bin、/sbin、/lib 这三兄弟/bin装的是所有用户都能用的基础命令ls、cp、mv、cat、echo、bash、mkdir。为什么强调基础因为它们在单用户救援模式下也必须可用——系统崩了要救的时候你能依靠的只有这批命令。/sbin装的是系统管理命令fdisk、mkfs、ip、iptables、reboot、shutdown。这些命令默认不在普通用户的PATH里因为它们的操作对象是整个系统不是你的文件。现在很多系统普通用户其实也能执行/sbin下的查询类命令但写操作依然需要 root。/lib和/lib64放的是共享库和内核模块libc.so、各类.so文件、/lib/modules/$(uname -r)/下的驱动模块。判断一个二进制依赖哪些库用ldd一看便知ldd /usr/bin/ls # linux-vdso.so.1 # libselinux.so.1 /lib64/libselinux.so.1 # libc.so.6 /lib64/libc.so.6注意ldd对不信任的二进制不要随便执行因为它某些实现会真的去加载程序。生产环境排查依赖稳妥做法是readelf -d 文件 | grep NEEDED。实际使用的经验如果你自己编译了一个命令行工具想让它全局可用标准落点是/usr/local/bin而不是/usr/bin。因为/usr/bin归包管理器管你手动丢进去的文件下次系统升级可能会被覆盖或者把包管理器搞出文件冲突yum/apt直接报错不干活。2.2 /etc配置文件的集中营改动最频繁也最危险/etc是整台机器上人味最重的目录几乎你所有的个性化调整都沉淀在这里。常用的几个文件/目录作用/etc/passwd用户账号信息密码哈希实际在/etc/shadow/etc/group用户组信息/etc/fstab开机自动挂载配置写错会开不了机/etc/hosts本地域名解析优先级高于 DNS/etc/resolv.confDNS 服务器地址/etc/systemd/system/systemd 服务单元文件自定义服务放这里/etc/sysconfig/RPM 系的服务参数网卡、防火墙等/etc/ssh/sshd_configSSH 服务配置这里的坑特别集中。第一个坑是/etc/resolv.conf很多同学手改完重启网络服务或者重启机器就没了——因为新版系统里它常常由网络管理服务动态生成。正确做法是改网卡配置文件或者网络管理服务自己的配置让它在生成resolv.conf时带上你的 DNS而不是跟生成器对着干。第二个坑是/etc/fstab。这个文件里写一个不存在的 UUID机器重启就会卡在救援模式。我的习惯是改完fstab之后先执行mount -a做一次校验能正常挂载再重启绝不带着未验证的fstab重启生产机器。第三个坑是权限。/etc下大量文件是600或640你chmod随手放宽等于把配置里的密钥、密码暴露出去。改配置目录权限前先ls -l看看默认是什么照抄就行。2.3 /dev、/proc、/sys、/run住在内存里的虚拟文件系统这四个目录有个共同点它们的内容不在硬盘上重启即消失或在运行时动态生成。理解这一点能省掉很多困惑。/dev是设备文件目录。/dev/sda是第一块 SCSI/SATA 磁盘/dev/sda1是它第一个分区/dev/null是黑洞写进去的东西直接丢弃读永远返回空/dev/zero是无限零做测试文件、清空数据常用/dev/tty代表当前终端。现代系统里这些文件由设备管理服务动态创建和删除你插一个 U 盘/dev/sdb就冒出来了。/proc是内核的体检报告目录cat /proc/cpuinfo # CPU 详细信息 cat /proc/meminfo # 内存使用详情 cat /proc/loadavg # 当前负载 cat /proc/PID/cmdline # 某个进程的启动命令 ls -l /proc/PID/cwd # 某个进程的工作目录排查问题的神技排查这个进程到底在哪个目录跑的它的启动参数到底是什么/proc比任何工具都直接。/sys和/proc有点像但更聚焦于设备和内核对象。比如把网卡收发包的一个参数调优、查看磁盘队列调度算法都在/sys/class/下面。做网卡中断绑核、IO 调度调优这类性能工作/sys是必去的地方。/run是临时运行时数据一般是 tmpfs内存文件系统。PID 文件、socket 文件、锁文件都在这儿。以前叫/var/run现在那个路径通常是/run的软链接。别把业务数据往这儿放重启全丢。2.4 /var最能惹事的一个目录/var名字来自 variable意思是会变的数据。它包含/var/log系统日志与业务日志messages、secure、cron、journalsystemd 二进制日志/var/lib程序运行时要保留的状态数据数据库文件、容器数据、包管理器元数据/var/spool队列数据比如定时任务队列、打印队列/var/cache缓存比如包管理器下载的.rpm/.deb/var/tmp比/tmp生命周期更长的临时文件这个目录是磁盘告警的头号元凶。日志会一直涨缓存会一直涨数据库会一直涨。所以生产环境一个非常实用的做法是把/var单独分区挂载。这样日志写爆时炸的是/var这一块根分区还活着你至少能登进去清理现场。另外提一句 systemd 的 journal默认它会把日志写到/var/log/journal/不限制大小。不干预的话一个月吃掉几十 GB 很常见。限制方式# 限制 journal 最大占用 500M journalctl --vacuum-size500M # 永久生效要改配置文件 vi /etc/systemd/journald.conf # SystemMaxUse500M systemctl restart systemd-journald2.5 /usr、/opt、/usr/local装软件的三个地盘别装错这三个目录的区分几乎是每个 Linux 新手的必踩坑。一句话总结/usr归发行版管/usr/local归你手动编译的软件/opt归第三方整包软件。/usr是Unix System Resources的缩写是系统中最大的目录包含/usr/bin 大部分用户命令真正的二进制在这里 /usr/sbin 系统管理命令 /usr/lib 库文件 /usr/share 与架构无关的共享数据文档、图标、模板、locale /usr/include C/C 头文件 /usr/src 系统级源码比如内核源码/usr/local的目录结构刻意和/usr保持对称bin、lib、share一应俱全因为它的设计目的就是手动安装的软件模仿系统目录放。你从源码编译一个工具./configure阶段加--prefix/usr/local装完就是标准的/usr/local/bin/xxx直接能全局调用干净且不污染包管理器。/opt则是给整个软件包自成一体的程序准备的。比如某个商业软件解压出来带自己的bin、lib、config你把它整个放到/opt/软件名/下即可。典型的用法是我们自己的业务应用/opt/myapp/{bin,conf,lib,logs}。目录谁管典型内容卸载方式/usr包管理器ls、nginx、python3yum remove/apt remove/usr/local管理员手动源码编译的工具make uninstall或手动删/opt管理员/厂商独立整包应用直接删目录一个高频误区把业务代码放到/usr/local下面。这在单机小规模时看着没问题但一旦要做多版本发布、回滚、独立磁盘配额/opt或独立数据盘才是合理落点后面第 4 节会细讲。2.6 剩下的那些住人目录/home、/root、/tmp、/boot 等/home是普通用户的家目录/home/用户名/下有Desktop、Documents、.bashrc、.ssh等。值得注意的是/home通常权限是700只有本人能进所以别人cd不进去是正常的不是权限坏了。/root是 root 用户的家目录。它不在/home/root下这是刻意设计如果/home挂在独立分区且挂载失败root 依然能登录进系统修复。同理/root目录权限是550或700普通用户别想窥探。/tmp是所有用户共享的临时目录权限1777——那个开头的1叫粘滞位sticky bit作用是这个目录里任何人都能建文件但只能删自己的文件。没有它任何用户都能删别人在/tmp里放的东西安全上就崩了。另外现代系统默认启用定时清理/tmp下超过一定天数的文件会被自动删除所以千万别把重要的 socket 或数据文件长期放在/tmp我见过应用因为 sock 文件被清掉而连接失败的案例。/boot放内核和引导相关文件vmlinuz-版本、initramfs-版本.img、grub/。这个目录必须放在大多数引导方式都能读取的位置所以老系统上常单独分区且不建议用 LVM 的奇怪配置。内核版本堆积也是它会撑爆的原因清理旧内核是个常规操作。/mnt是给管理员临时挂载用的空目录/media是给系统自动挂载可移动介质用的插 U 盘自动挂在/media/用户名/卷标。/srv预留为本机提供的服务数据实际用得少很多人拿它放 FTP 或 Web 数据。/lostfound是 ext 系列文件系统专有用来存放损坏恢复出来的文件碎片平时是空的别删。3. 目录结构和分区、挂载是怎么绑在一起的3.1 挂载点怎么选拿 U 盘讲最清楚新买一块盘fdisk分完区、mkfs格式化完此时它还是个孤岛你必须把它挂到目录树上才能访问mkdir -p /data mount /dev/sdb1 /data df -h | grep data # /dev/sdb1 100G 33M 100G 1% /data执行完后/data这个目录的内容就变成了/dev/sdb1里的内容。这里有个必须记住的行为如果挂载点目录里原来有文件挂载之后这些文件会被遮住看不见但没删卸载后又会重新出现。这个特性有时候能救命但更多时候是事故源头——比如你把应用日志写在/data/logs结果有天/data没挂上fstab 写错或盘故障应用就往根分区的/data/logs里写把/写满。这属于典型的没挂载导致写错位置故障排查时先df -h看挂载点对不对。3.2 安装系统时的分区方案怎么定才不后悔没有万能方案但有可以参考的起点。下面这套是中小型业务服务器的常见配置我按一台 500GB 系统盘 16GB 内存来算挂载点建议大小理由/boot1G每个内核加 initramfs 约 100~200M留 3~5 个内核的空间/50~100G系统本体加临时空间装常规软件足够/var50~200G日志、缓存、容器数据增长最快/tmp10~20G 或 tmpfs避免临时文件挤爆根分区/home按需多人登录的机器才有意义/data剩余全部业务数据、应用、备份swap见下方计算内存不足时的缓冲swap 的算法老经验是内存小于 8G 就给内存的 2 倍8G 以上给等量或 1.5 倍但这条规则在现代已经不太适用了。更实际的判断依据是你是否要用休眠功能休眠需要把内存内容写入 swap所以 swap 必须大于物理内存如果不用休眠纯当应急缓冲给 4~8G 甚至更少都行很多生产环境干脆不配 swap靠监控和内存扩容解决问题。一个反直觉的注意点/usr一般不建议单独分区。因为/usr和/的依赖关系太紧密一旦/usr挂载失败系统连基础命令都找不到救援会非常麻烦。同理/etc也不单独分区。分区工具方面fdisk处理 MBR 分区gdisk/parted处理 GPT。现在 2TB 以上的盘必须用 GPT这一点选错会导致分区表识别不全。另外如果有条件用 LVM逻辑卷管理会舒服很多——它能在线扩容不用停机重新分区。代价是多一层抽象排查问题时多敲几条命令。3.3 挂载信息存在哪/etc/fstab 与它的小兄弟/etc/fstab是开机自动挂载的账本每行六个字段UUIDxxxx-xxxx /data xfs defaults,noatime 0 0从左到右依次是设备标识推荐用 UUID不用/dev/sdb1因为盘符顺序可能变、挂载点、文件系统类型、挂载选项、dump 备份标志、fsck 检查顺序。这里面有两个坑位值得展开挂载选项里的noatime很实用。默认每读一次文件都要更新访问时间戳这在读密集场景下会产生大量额外写操作。加上noatime可以减少 IO对数据库和日志盘有实际收益。defaults本身就包含了rw,suid,dev,exec,auto,nouser,async一整套别以为写defaults就等于什么都不设。最后一个字段是 fsck 顺序根分区写1其他分区写2不检查的写0。写反了或者多写几个1开机时多个文件系统并发检查慢且容易出问题。改fstab之后一定记得先mount -a验证这条命令会把 fstab 里还没挂载的项全部挂一遍报错会当场告诉你而不是等到下次重启才发现机器起不来。4. 实操从零规划一套规范的服务器目录前面讲的都是规矩这一节直接动手把一台新服务器从空目录搭到能跑业务。4.1 目录规划与创建假设我们要部署一套 Java Web 应用规划如下应用本体放/opt业务数据、日志、备份放独立的/data分区。# 1. 建应用根目录注意用 -p 一次建多层 mkdir -p /opt/myapp/{bin,conf,lib,logs,temp,work,webapps} # 2. 建数据分区下的业务目录 mkdir -p /data/{app,logs,backup,tmp,upload}这个结构不是我瞎编的它照着 Servlet 容器的CATALINA_BASE约定来的bin放启动脚本conf放配置lib放依赖 jarlogs放日志temp和work放运行时编译产物webapps放部署包。好处是团队内所有人的应用目录完全一致运维写脚本不用问你们日志在哪闭眼就是/data/logs/应用名/。为什么日志要放到/data/logs而不是/opt/myapp/logs因为/opt通常和系统盘在一起日志涨起来会挤爆根分区而/data是独立盘写满也不影响系统运行。这是物理隔离思路比事后du找大文件要轻松得多。创建单个应用目录时我喜欢再加一层版本目录配合软链接做发布mkdir -p /data/app/myapp/releases/20250101_1 mkdir -p /data/app/myapp/releases/20250108_1 ln -s /data/app/myapp/releases/20250108_1 /data/app/myapp/current发布新版本时新建20250115_1目录解包测通之后把current这个软链接重新指向新目录再重启服务。回滚就是ln -sfn指回老目录。整个切换动作是原子的ln -sfn的本质是创建新链接再改名比覆盖式发布安全得多也比备份旧包再恢复快得多。4.2 用户、用户组与目录权限的配合目录规划完了权限不对等于白干。原则有三条应用不用 root 跑、同组共享用 setgid、敏感目录收紧到 750。# 1. 建专属用户和组-r 表示系统用户-s 指定不可登录 shell groupadd -r myapp useradd -r -g myapp -s /sbin/nologin -d /opt/myapp myapp # 2. 改属主属组 chown -R myapp:myapp /opt/myapp chown -R myapp:myapp /data/logs /data/app # 3. 收紧权限 chmod 750 /opt/myapp /data/logs /data/app chmod 640 /opt/myapp/conf/*.properties关于setgid这是个很少被讲透但极其好用的机制。给目录加上g位的schmod 2775 /data/upload ls -ld /data/upload # drwxrwsr-x ... /data/upload效果是在这个目录里新建的文件和子目录属组自动继承父目录的属组而不是继承创建者的主组。多人协作的目录比如运维组共享的脚本目录、多个服务共享的上传目录不加这个位会出现A 建的文件 B 改不了的经典扯皮问题。2775里开头的2就是 setgid 位。权限实操心得chmod -R 777是万恶之源它解决不了权限问题只是把问题藏起来。真正该做的是先确认谁需要什么权限然后精确给750/640/770再把人加进对应的组。用777跑业务相当于把保险柜门拆了当储物架用。另外/opt/myapp/conf里如果存了数据库密码权限必须收紧到640甚至600属主是应用用户。曾经在审计里见过配置文件644加明文数据库密码服务器一被扫就是全库泄露。这种事成本极低改一下权限就防住了。4.3 Java Web 项目的标准目录结构长什么样热词里出现了java web 项目标准目录结构这里说清楚两个层面的标准很多人会混淆。第一个层面是源码工程的目录结构Maven 约定myproject/ ├── pom.xml 构建描述 ├── src/ │ ├── main/ │ │ ├── java/ 源码 │ │ ├── resources/ 配置与资源文件 │ │ └── webapp/ Web 资源JSP、静态文件、WEB-INF │ │ ├── WEB-INF/ │ │ │ ├── web.xml │ │ │ └── lib/ │ │ └── static/ │ └── test/ │ └── java/ 测试代码 └── target/ 构建产物不提交到版本库这是开发机器上的结构target/目录是构建输出不该进 Git。第二个层面是部署到服务器后的目录结构这个才是跟本文主题相关的。部署形态通常是打成一个 war 或 fat jar落点有两种一种是容器部署war 包丢进容器的webapps/容器会自己解压成同名的爆炸目录WEB-INF/classes和WEB-INF/lib就是它的运行类路径。此时要注意work/目录——容器会把 JSP 编译成 Java 再编译成 class 放在这里如果work权限不对或磁盘满页面会报 500 而且日志里看不出明显原因。另一种是独立进程部署现在更主流打一个可执行 jar配一个启动脚本# /opt/myapp/bin/start.sh #!/bin/bash APP_HOME/opt/myapp CURRENT/data/app/myapp/current nohup java -server -Xms2g -Xmx2g \ -Dspring.profiles.activeprod \ -Dlogging.file.name/data/logs/myapp/app.log \ -jar $CURRENT/myapp.jar /dev/null 21 echo $! /run/myapp.pid这里有几个目录细节值得说日志路径用启动参数显式指定到/data/logs不依赖工作目录PID 文件写/run重启自动清理jar 包路径指向current软链接这样切换版本不用改脚本。整套逻辑里目录和软链接承担了版本管理的职责简单到小学生都能理解但非常可靠。4.4 用软链接把目录搬到大盘服务器跑着跑着根分区满了是最常见的突发情况。这时候如果磁盘还有空余分区最快的止损办法是把大目录搬过去用软链接接回来。以/var/lib/docker为例# 1. 停服务避免写入 systemctl stop docker # 2. 复制数据-a 保留权限和属主 cp -a /var/lib/docker /data/docker-data # 3. 确认复制完整对比大小 du -sh /var/lib/docker /data/docker-data # 4. 删原目录并建软链接 rm -rf /var/lib/docker ln -s /data/docker-data /var/lib/docker # 5. 启服务并验证 systemctl start docker docker info | grep Docker Root Dir这里很容易出错的地方是第 4 步rm -rf之前一定确认第 2、3 步成功否则数据就真没了。我个人的习惯是先改名而不是直接删mv /var/lib/docker /var/lib/docker.bak ln -s /data/docker-data /var/lib/docker # 服务验证通过跑几天没问题后再删 .bak多留一步缓冲成本是几十 GB 临时空间收益是万一链接没生效还能秒回滚。再说说软链接和硬链接的区别因为这两个经常在目录场景下被搞混。软链接是一个独立的小文件内容是目标路径可以跨分区、可以指向目录、目标删了它就变成断链。硬链接本质上是指向同一个 inode 的另一个名字不能跨分区、不能指向目录、删除原文件不影响访问但所有硬链接都删掉数据才真释放。理解 inode 这个层面对排查磁盘删了文件但空间没释放的经典问题很关键——因为还有进程持有那个已删除文件的句柄# 空间没释放找到持有已删除文件的进程 lsof L1 | head # 重启或 reload 对应进程即可释放5. 排查实录目录结构相关的典型故障5.1 根分区写满从告警到定位的完整路径现象SSH 登不上或者登上了但执行命令报No space left on device。这就是根分区满了而且往往是因为某个本该在独立分区的目录被写爆了。排查顺序非常固定照着敲就行# 第一步看整体确认是哪个挂载点满 df -h # 第二步从根目录逐层往下找大目录注意排除其他挂载点 du -sh /* 2/dev/null | sort -rh | head -10 # 第三步锁定目录后继续下钻 du -sh /var/* 2/dev/null | sort -rh | head -10 # 第四步找大文件超过 500M find / -xdev -type f -size 500M -exec ls -lh {} \; 2/dev/null-xdev这个参数特别重要它的作用是不跨越文件系统边界也就是查/的时候不会跑到/proc、/data这些挂载点上速度能快十倍输出也更聚焦。定位到之后常见的凶手和处置方法占满原因判断依据处置方式应用日志没切割/var/log或业务日志目录巨大清历史日志配置 logrotatesystemd journal/var/log/journal几十 Gjournalctl --vacuum-size1G已删除文件被进程持有df显示占用du对不上lsof L1找到进程后重启包管理器缓存/var/cache/yum或aptyum clean all临时文件堆积/tmp或/var/tmp清理检查清理策略数据库/容器数据错放/var/lib下异常膨胀迁移到独立盘参考 4.4 节这里最值得警惕的是第三种df说满du却找不出对应文件。这不是灵异事件而是文件被删了但进程还在往里面写——inode 没释放空间就没还回来。第一次遇到这个现象时我盯了两个小时最后在lsof里看到一行(deleted)才反应过来。5.2 解压中文文件名乱码根因和解法这个问题的热词也出现了说明踩坑的人真不少。现象是在 Windows 上打包的 zip传到 Linux 用unzip解出来中文文件名全是问号或方块。根因是编码不一致。Windows 的中文 zip 通常用 GBK 编码存文件名而 Linux 默认按 UTF-8 去解读两套编码对不上号。解决方案分两种情况# 情况一unzip 版本较新部分发行版支持 -O 参数 unzip -O GBK files.zip -d ./target # 情况二系统自带 unzip 不支持 -O会报 invalid option # 用带编码支持的实现或者换工具 7z x files.zip -o./target -mcp936-mcp936里的 936 是 GBK 的代码页编号。如果文件名已经在解压时变成了乱码还有一步补救# 对已经乱码的文件名做编码转换 convmv -f GBK -t UTF-8 -r --notest ./target-r表示递归处理子目录--notest表示真正执行不加这个参数只会打印预演结果不会改。另外如果是 tar 包乱码通常不是编码问题而是打包时的 locale 环境不同用tar --help里的编码相关选项或者干脆在打包端统一用 UTF-8 就一劳永逸了。经验跨平台传文件的场景最省心的做法是打包前统一用 UTF-8 文件名。真要传 GBK 的包提前记好上面两条命令能省下不少搜索时间。5.3 目录相关高频问题速查表现象可能原因一条命令定位磁盘没满但写文件失败inode 耗尽小文件太多df -i重启后文件消失目录是 tmpfs/tmp、/rundf -hT /tmp改了fstab后机器起不来UUID 写错或挂载点不存在救援模式下注释掉该行挂载后原目录文件不见了文件被挂载遮盖未丢失umount后查看软链接指向失效目标被移动或删除ls -lreadlink -f应用读不到配置工作目录不对用了相对路径ls -l /proc/PID/cwd权限明明给了还是拒绝上级目录缺少执行位namei -l /路径/文件目录无法删除有进程占用或挂在挂载点lsof D 目录namei -l这条命令值得单独夸一句它会把你给的路径逐层列出权限一眼就能看出是中间哪一层目录缺了x位。Linux 里目录的x位含义是可以进入和穿透很多人只盯着最终文件权限忽略了上一级目录没有x就根本走不到用namei五秒钟定位。6. 一点个人经验目录规范是便宜的保险我在实际维护中最大的体会是目录结构的价值不在于整齐好看而在于它决定了故障发生时的可控范围。把/var、/data拆成独立分区把日志和数据分开放把应用跑在非 root 用户下把发布切换做成软链接——这四件事加起来可能只花你搭建一台服务器时的二十分钟但它们能在磁盘写满、需要回滚、权限被扫的时候把一场事故压缩成一次重启。顺带分享一个我一直在用的小习惯每台新机器部署完成后我会跑一遍df -hT、ls -ld /opt /data /var /tmp把输出粘到运维文档里作为这台机器的目录基线。之后一旦有人改了分区或权限对比基线就能立刻发现异常。这个动作看起来有点笨但比事后追查这块盘什么时候挂上去的要轻松太多。