mkdir、rmdir本节摘要:文件层面的增删改上一节讲完了,这一节专门讲目录的「建」与「拆」:
mkdir(创建目录)和rmdir(删除空目录)。这两个命令表面朴素,但藏着两个关键设计——mkdir -p的「幂等」特性(目录已存在不报错、还能一口气建多层父目录),以及rmdir固执地「只删空目录」的安全意图。你会理解为什么几乎所有生产脚本里mkdir都跟着-p,以及为什么删一个非空目录必须退回去用rm -r——rmdir的「无能」恰恰是它在脚本里的价值。读完这节,你建目录、拆目录的姿势就专业了。
内容来源:原项目「Linux 命令大全」
command/mkdir.md、command/rmdir.md,精选并套用体系化模板。
阅读完本节,你应当能够:
mkdir 创建单个或多个目录,理解 -p(递归建父目录 + 幂等)、-m(设权限)的用法。mkdir 几乎一律加 -p(幂等妙用)。rmdir 删除空目录,理解它「只删空目录」的设计意图。rm -r,而 rmdir 故意不做这件事。mkdir -p a/b/c 一口气建多层目录,用 rmdir -p a/b/c 一口气拆多层。mkdir -p:幂等与递归建父mkdir 不加任何选项时,行为很严格:只能建一层目录,且父目录必须存在、目标目录不能已存在。
mkdir /tmp/a # OK, /tmp 存在, a 不存在 mkdir /tmp/a # 报错: a 已存在! mkdir /tmp/x/y/z # 报错: /tmp/x 都不存在, 怎么建 y/z?
这种严格在交互式下还好,但在脚本里是灾难——同一个脚本跑两次第二次就报错;想建深层目录得一层层建。所以 mkdir 有个 -p 选项,它做两件事:
mkdir -p /tmp/a # a 已存在也不报错(幂等) mkdir -p /tmp/x/y/z # /tmp/x、/tmp/x/y、/tmp/x/y/z 一口气都建出来(递归)
-p 让「目录已存在」不再是错误,而是静默成功。这意味着同一段 mkdir -p 你跑多少次都安全。-p 会自动把路径上缺失的每一级父目录都建出来,不用你一层层敲。关键概念:脚本里造目录几乎必加
-p,这是个铁律。它让脚本「幂等」(可重复执行而不出错),也省去你逐层创建的麻烦。看到任何mkdir不带-p的脚本,都要多一分警惕——它可能在第二次运行时报错。
rmdir:只删空目录的安全设计rmdir 的「限制」比 mkdir 还严:只能删空目录,目录里只要有一个文件或子目录,就拒绝删除。
rmdir /tmp/empty # OK, 空目录 rmdir /tmp/nonempty # 报错: Directory not empty
这个限制看起来很「笨」,但它是故意的安全设计。删目录是个高危操作(目录下可能藏着无数文件),rmdir 故意不让你「一个命令清空整棵子树」。想删非空目录,你必须显式用 rm -r,把「我知道我在删整棵树」的责任交给你。
💡 技巧:在脚本里,
rmdir的「只删空目录」反而是个特性——它保证了「我删的目录一定是空的,不会误删数据」。如果你要做一个「清理临时目录,但只在它空了的时候才删」的逻辑,rmdir比rm -rf安全得多:目录里有东西它会报错而不是闷头删光。
mkdir 常用组合mkdir mydir # 建单个目录 mkdir dir1 dir2 dir3 # 同时建多个目录 mkdir -p a/b/c # 递归建多层(父目录不存在也建) mkdir -p /opt/app/{conf,log,data} # 配合花括号展开: 一口气建三个子目录 mkdir -m 700 secret # 建目录时直接设权限 700(仅属主可读写执行) mkdir -pv a/b/c # 递归 + 显示过程(verbose)
mkdir -p + 花括号展开 是脚本里建项目骨架的利器:
mkdir -p project/{src,doc,test,build} # 一次建成: # project/src project/doc project/test project/build
这条命令利用了 Shell 的花括号展开({a,b,c} 展开成三个词),配合 mkdir -p,一行建好整个项目的标准目录结构。这在你初始化新项目时极省事。
mkdir -m:建目录时设权限mkdir -m 700 secret # 只允许属主访问 mkdir -m 755 normal # 属主全权, 其他人只读+进目录 mkdir -m 1777 /tmp/shared # 加 sticky bit(1开头), 公共可写但不能互删
-m 直接指定权限位(八进制),省去建完再 chmod 的两步。权限位的具体含义留到第 5 章,这里只要知道「建目录时可以一步到位设权限」。
💡 技巧:
/tmp目录的权限是1777(那个开头的1是 sticky bit),它的作用是「所有人都能往里写,但只能删自己创建的文件」。这就是为什么/tmp谁都能用,却没人能删别人的东西。mkdir -m 1777能复刻这个行为。
rmdir 常用组合rmdir empty # 删空目录 rmdir -p a/b/c # 递归删: 删 c, 删 b, 删 a(每一级都必须空) rmdir -v empty # 显示删除过程
rmdir -p a/b/c 会先删最深的 c,如果删完 b 空了就删 b,a 空了就删 a——一口气拆多层。但只要任何一级不为空,整个操作就在那一级停下并报错。这和 mkdir -p 是对称的设计。
# 标准的"建工作目录"模板 WORKDIR=/opt/myapp/work mkdir -p "$WORKDIR"/{input,output,tmp} # 一行建好三个子目录, 幂等 cd "$WORKDIR" || exit 1 # 切进去, 失败就退出
这段代码无论跑多少次都安全(幂等),无论 WORKDIR 是否存在都能建成,这是生产脚本的标配写法。对比不加 -p 的版本:
# 危险写法(反面教材) mkdir /opt/myapp/work/input # 父目录不存在? 报错 mkdir /opt/myapp/work/output # 同上
-p 导致脚本第二次运行报错mkdir /opt/myapp # 第一次运行: OK # 第二次运行: mkdir: cannot create directory '/opt/myapp': File exists
脚本里不加 -p,mkdir 对已存在的目录会报错,导致脚本中断(尤其配合 set -e 时)。解法就是无脑加 -p,把「已存在」变成「正常」。
rmdir 删不了非空目录rmdir /tmp/mydir # rmdir: failed to remove '/tmp/mydir': Directory not empty
很多人第一次用 rmdir 都会撞这个错。它不是 bug,是设计——rmdir 就是只删空的。要删非空目录:
rm -r /tmp/mydir # 递归删(会逐个问) rm -rf /tmp/mydir # 递归强删(不问, 危险)
⚠️ 注意:从
rmdir(安全)切到rm -rf(危险)时,务必确认目录内容确实可以删。rmdir的「拒绝」其实是在提醒你「这里有东西,你想清楚」——别惯性思维地直接rm -rf绕过它。
mkdir -p 改变了错误类型mkdir -p /root/x # 普通用户执行: 权限不足, 失败 mkdir /root/x # 普通用户执行: 同样失败
-p 不能绕过权限限制——你仍然需要对父目录的写权限。但它改变了「目录已存在」这个错误的处理:不加 -p 会报错,加了 -p 静默成功。-p 只解决「已存在」和「父目录缺失」两类问题,不解决「权限不足」。
mkdir -p 与软链接的交互mkdir -p /opt/app # 如果 /opt 是个软链接指向 /data/opt # mkdir -p 会在物理位置 /data/opt 下建 app
当路径里有符号链接时,mkdir -p 会顺着链接走到底。这通常是想要的,但偶尔会让你困惑「我建的目录到底在哪」。建完后 pwd -P(上一节讲的)或 realpath 能帮你确认物理位置。
mkdir -m 与 umask 的关系mkdir dir # 默认受 umask 影响: umask 022 时, 权限是 755 mkdir -m 777 dir # 显式指定, 绕过 umask, 权限就是 777
不加 -m 时,新目录的权限是 777 & ~umask(umask 是「要屏蔽的权限」)。加了 -m,权限就是指定的值,不受 umask 影响。这点在脚本里很重要——脚本依赖确定的权限,不能被运行者的 umask 左右,所以关键目录要加 -m。
mkdir -p 是脚本标配:幂等(已存在不报错)+ 递归建父目录,几乎所有生产脚本里的 mkdir 都加 -p。mkdir -m 建目录时直接设权限,绕过 umask,脚本里关键目录必加 -m 确保权限确定。mkdir -p + 花括号展开(a/{b,c,d})是一行建项目骨架的利器。rmdir 只删空目录是故意的安全设计,删非空目录必须用 rm -r——这个「无能」恰恰是它在脚本里的价值。rmdir -p 与 mkdir -p 对称:一口气拆多层,任一级非空就停下。-p 第二次报错、rmdir 删非空必失败、-p 绕不过权限、umask 影响默认权限。目录的建与拆讲完了,但还有一个根本问题没回答:「文件到底是什么?为什么 ls -l 第二列那个硬链接数有时是 1、有时是 2?为什么删一个文件不释放空间?」下一节是本章的高潮——i 节点与链接。我们会用 stat 看 i 节点的全貌,用 ln 建硬链接、ln -s 建软链接,把硬链接与软链接的本质差别讲透。理解了 i 节点,你对 Linux 文件系统的认知会彻底升级。