ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Linux mkdir命令详解:从基础创建到权限控制与批量自动化

Linux mkdir命令详解:从基础创建到权限控制与批量自动化 刚接触 Linux 的人往往学会的第一条命令就是mkdir。这个命令看起来简单得不能再简单就是创建目录嘛。但用得多了你会发现越是基础的工具越藏着不少讲究。同样是创建目录你是只需要建一个空文件夹还是要批量生成一套复杂的前端目录结构是只在自己家目录里捣鼓还是在生产服务器的/data下操作这背后对mkdir的用法要求完全不一样。这篇文章就专门把mkdir掰开揉碎从最基础的参数讲起再到多目录批量创建、权限控制、常见误区和排查手段基本上我能想到的场景都覆盖到希望能帮你把这个命令用得像喝水一样自然。1. mkdir 的底层逻辑与基础用法1.1 目录的本质是什么想真正理解mkdir的各种用法得先搞清楚目录在 Linux 里到底是什么。很多人把它理解成 Windows 里的“文件夹”这个类比大体没错但容易误导。在 Linux 的哲学里“一切都是文件”目录也是文件只不过它是一种特殊的文件。普通文件存放的是数据目录文件存放的是一个清单里面记录着“文件名 —— inode 编号”的对应关系。当你运行ls命令时系统其实就是把这个目录文件的内容读取出来再翻译成人能看懂的列表。这就带来一个很实际的影响创建目录本质上是在当前文件系统里申请一个 inode然后在这个 inode 上初始化一个空的目录数据块。这个操作能不能成功取决于你当前所在的父目录是否允许你写入和运行。如果没有写权限mkdir就会直接报Permission denied。所以你看Linux 下仿佛到处都是“权限不够”的报错其实从底层就注定了。理解了这一点再来看mkdir的几个常用参数就能明白它为什么要这样设计。1.2 mkdir 的基本语法和常用参数mkdir的全称是 make directories语法非常直白mkdir [选项]... 目录名...常用参数其实就这几个但每一个都有它的使用场景参数作用典型场景-p递归创建多级目录目录存在时不报错一次性创建a/b/c/d这样的层级-m指定权限模式覆盖默认权限创建带特殊权限的目录如mkdir -m 700-v显示创建过程配合-p使用输出每一条创建信息--mode同-m属长格式写法脚本中追求可读性时使用注意-p这个参数特别重要它不仅是“递归创建”这么简单还隐含着一个“幂等”特性如果目标目录已经存在mkdir -p不会报错直接静默跳过。而普通的mkdir遇到目录已存在时会抛出一条cannot create directory xxx: File exists。这个差异在写脚本时非常关键。一个健壮的部署脚本里需要“确保目录存在”时往往都会用mkdir -p而不是先判断再创建因为后者永远是先有鸡还是先有蛋的坑。1.3 第一次用 mkdir 建目录看这三个实例如果刚刚接触 Linux下面三组命令值得亲手敲一遍感受一下参数的区别。先是最普通的创建方式cd ~ mkdir test_dir ls -ld test_dir新目录的默认权限是rwxr-xr-x也就是 755。这中间的“为什么是 755”后面专门有段落来讲这里先记着现象。再来看递归创建和幂等性mkdir -p /tmp/test_dir/a/b/c mkdir -p /tmp/test_dir/a/b/c第一次执行会创建完整层级第二次执行什么都不输出也不会报错。你可以用find /tmp/test_dir验证一下目录结构。最后是提高权限的场景。很多时候你创建一个工作目录并不想默认允许其他用户读进去可以这样做mkdir -m 700 ~/private ls -ld ~/private输出里drwx------就说明只有你自己能进入。这类目录常见于存放密钥、私密脚本或一些临时敏感的下载文件。2. mkdir 的权限控制与 umask 机制2.1 为什么新建目录默认是 755这是一个很经典的面试问题也是运维排查权限问题时必须理解的知识点。新建目录的实际权限并不是一个固定值而是由“基本权限”和“权限掩码”共同决定的。Linux 下新建目录的基本权限是0777也就是rwxrwxrwx但创建时系统会拿这个值和当前的umask做一个按位取反后的“与”操作。大多数发行版默认的umask是022所以实际生成的权限就是0777 ~022算出来是0755。你可以在当前 shell 里直接输入umask查看自己的掩码值umask # 输出通常是 0022如果你的系统里umask是0022那默认创建目录是 755如果是0027那默认就是 750。很多公司内部安全基线要求/home下用户目录的权限是 750所以会修改登录脚本里的umask。这直接影响了你在用户家目录下随手创建的目录能不能被别人看到理解这条链路后排查权限问题时就不会两眼一抹黑了。2.2 用 -m 参数绕过 umask 的干扰如果你创建目录时不想要默认权限可以通过-m参数直接指定。这个参数的优势是它不受当前umask影响因为你在命令行里明确给出了权限系统会直接按这个权限创建。举几个实际常用的例子# 创建只能本人访问的备份目录 mkdir -m 700 /backup/$(date %F) # 创建临时共享目录允许组内用户读写但其他人没有任何权限 mkdir -m 770 /project/shared # 创建所有人都能读写的临时目录但不允许删除别人的文件粘滞位 mkdir -m 1777 /tmp/myshare这里有个细节很多人容易忽略mkdir -m 1700这种四位数权限第一位其实代表特殊权限位。1是粘滞位2是 setgid 位4是 setuid 位。普通场景下你用不上但在多用户环境或 Web 服务里面setgid 位非常有用。比如你把某个目录设为2755那么在该目录下新建的文件和子目录会自动继承父目录的属组而不是默认的当前用户的私有组。这一步在团队协作目录里能省掉很多人为改组的操作。2.3 目录权限的真正含义读写执行缺一不可很多新手会困惑目录的“执行权限”到底是干嘛的简单讲目录的读权限决定你能不能列出里面的目录项写权限决定你能不能在里面新建和删除文件而执行权限决定你能不能 “穿越” 这个目录也就是cd进去或者访问它下面的子路径。这三者常常需要组合起来用。比如你只想让别人能进入目录查看但不能列出目录内容那就应该设置为111只有执行权限这种场景虽然少见但在某些安全加密目录的场合会用到。反过来一个目录如果有写权限但没执行权限你从它下面拿文件路径访问时会被卡住光有权限却不能穿越。实际运维中最常见的权限问题其实出在“粘滞位”和“共享目录”的组合上。大家应该都熟悉/tmp目录它本身权限是drwxrwxrwt最后那个t就是粘滞位。因为/tmp对所有人开放如果不加粘滞位任何用户都能删除别人的临时文件这显然是不可接受的。所以在做共享目录时一定要记得加上1777或至少确认有粘滞位不然上线后会被安全团队点名。3. mkdir 的高阶玩法批量创建与自动化3.1 一条命令创建一整棵目录树实战里我们经常需要一次性建好多层目录。比如新建一个 Java 项目的骨架需要这样的结构src/main/java src/main/resources src/test/java你要是用裸的mkdir挨个建得敲好几条命令而且父目录不存在时还会报错。正确姿势是直接加-p一次性到位mkdir -p src/{main/{java,resources},test/java}这里用到了 bash 的花括号扩展brace expansion。{main/{java,resources},test/java}展开后就生成了四个路径mkdir -p会自动补全它们各自的父级目录。执行完find src看一下整棵结构就出来了。这个写法配合-v参数还能看到每一步创建过程在脚本调试阶段非常有帮助mkdir -pv logs/{nginx,app/mysql,tmp}输出会逐行显示创建了哪个目录一旦哪条路径因为权限或命名问题失败能立刻定位到具体是哪一层出的错。3.2 循环批量创建有规律的目录如果说花括号扩展适合创建一组固定名字的目录那需要批量创建有编号的目录就得靠循环了。比如你要为每天的数据文件建立一个独立目录一个月 31 天总不能手敲 31 个mkdir吧。在 bash 里这样写for i in $(seq -w 1 31); do mkdir -p data/2025/$(date %m)/day_$i doneseq -w会生成 01 到 31 的补零编号目录名就变成day_01、day_02这种格式排序起来非常舒服。这种结构在日志归档、测试报告生成这些场景里非常实用。如果你是在 Python 或 Go 的脚本里做类似的事可以调用系统命令但更优雅的做法是直接用语言自身的目录创建接口。底层逻辑和mkdir一致本质上都是同一套系统调用。3.3 双目录交叉创建与初始化目录骨架还有一种比较风骚的用法是同时创建“目录 子目录”的矩阵。比如你想把一组模块按测试环境和生产环境分别建目录mkdir -p deploy/{dev,prod}/{config,scripts,backup}这一条命令就创建了 6 个目录deploy/dev/config、deploy/dev/scripts、deploy/dev/backup、deploy/prod/config以及另外两个prod下的目录。做环境初始化时非常省事。如果还要初始化每个目录的说明文件可以配合 touchcd deploy/dev touch README.md cd ../../..不过在自动化脚本里我不建议用cd来回跳容易出错更适合的做法是touch deploy/dev/README.md这种全路径写法。另外mkdir和install命令常放在一起比较。install -d本质上等同于mkdir -p但install还可以配合-o、-g、-m直接设置目录的属主、属组和权限。比如在安装脚本里创建一个服务目录时这样一行就能搞定install -d -o nginx -g nginx -m 750 /var/www/mysite相比之下mkdir创建完你还得再执行chown和chmod步骤就多了。所以如果你在写自动化部署脚本多想想install -d这个替代项会让脚本干净不少。4. mkdir 在实战场景中的组合应用4.1 部署服务时创建标准目录结构我每次在服务器上部署一个新的 Web 服务都会先搭好固定的目录骨架。这个习惯是从踩过几次坑之后养成的一开始是无所谓代码放哪、日志放哪、配置放哪都是想到哪建到哪。等服务出了问题要排查时才发现日志散落在五六个不同路径找起来像大海捞针。现在我惯用的初始化命令是这样的mkdir -p /opt/app/{bin,conf,logs,data,tmp} chown -R appuser:appgroup /opt/app chmod 750 /opt/app这里有几个细节值得展开说。第一/opt/app这种业务软件路径尽量不要直接放在/root或普通用户家目录下因为它可能要被系统服务访问而家目录本身的权限和挂载策略未必合适。第二创建完目录后立刻chown这一步很重要因为mkdir建出来的目录属主是当前执行用户如果服务要以appuser身份运行目录权限不对会导致启动时无法写入日志或临时文件。我见过很多人明明目录都建好了服务却报Permission denied最后发现是忘了改属主。第三chmod 750是为了阻止其他无关用户读取程序配置配置里经常有数据库密码一类的敏感信息宁可紧一点。4.2 日志按日期分目录的自动化脚本日志目录大概是mkdir用得最频繁的生产场景了。服务每跑一天就产生一批日志按日期归档是一个刚需。下面是我在定时任务里经常写的一段脚本LOG_BASE/var/log/myapp TODAY$(date %Y%m%d) mkdir -p $LOG_BASE/$TODAY千万别小看这三行第 3 行加不加-p区别很大。如果没有-p一旦某天/var/log/myapp被误删或者没有创建脚本直接失败日志也就写不进去了。有了-p不管父目录是否存在都会确保最终目标目录可用。这里还有个细节是日期命令的引用。$(date %Y%m%d)里的日期格式必须加引号吗不一定但如果你在mkdir后面跟着多条命令且路径中可能包含空格那就需要养成交叉检查的习惯。推荐路径变量一律加双引号这是一个从无数次文件路径带空格导致脚本炸掉的经历里总结出来的教训。尤其是某些通过 Windows 工具上传的配置路径中间被塞进空格时不加引号会拆成两个参数然后创建出莫名其妙的多余目录。4.3 嵌入式环境与镜像构建中的目录预创建很多人觉得mkdir就是命令行里敲敲其实在嵌入式 Linux 开发中它也是构建根文件系统的关键工具之一。交叉编译环境里往往需要先创建一套目标机的根目录骨架比如/root、/dev、/proc、/sys、/etc、/usr/bin、/var/log等才能往里面拷贝 busybox、库文件和配置。我刚开始做嵌入式时是手动一条条mkdir敲的后来改成脚本。这个过程中最关键的一点是这些目录的权限必须提前设计好。例如/root目录权限应该是700/tmp应该是1777而/dev目录在系统启动后通常会被 devtmpfs 或 mdev 自动挂载但你做镜像时还是要先建一个空目录当作挂载点。所以嵌入式构建脚本里我常写的批处理大概是这种样子mkdir -p -m 755 $ROOTFS/{etc,usr/bin,usr/sbin,var/log} mkdir -p -m 700 $ROOTFS/root mkdir -p -m 1777 $ROOTFS/tmp mkdir -p -m 555 $ROOTFS/proc $ROOTFS/sys注意最后一行-m 555/proc和/sys在运行态是内核伪文件系统哪怕设置了 555也只是作为挂载点的默认权限不会影响挂载后的实际表现。但如果你忽略权限设置某些检查工具可能会报出安全告警。总之在做镜像或基础系统时目录权限要在一开始就固化下来别等机器跑起来再慢慢改因为很多配置都假定目录的默认权限是正确的。4.4 与 tar、find、rsync 等命令的协同技巧mkdir通常不是单独使用的它经常在一整条命令行里和其他工具配合。举两个我几乎天天用到的例子。第一个是用 tar 解压时自动创建目标目录。很多人会用tar -xzf archive.tar.gz -C /tmp/target但如果/tmp/target目录不存在tar 会报错。虽然部分 tar 版本能自动创建但如果你想显式控制可以先用mkdir -p保证目录存在再解压。这种情况下我一般把创建和解压写成一行mkdir -p /tmp/target tar -xzf archive.tar.gz -C /tmp/target这里的作用是前一条命令成功才执行后一条不容易出现目录没建成就解压到别处的诡异情况。第二个是配合find做批量归档。比如想把某个目录下超过 30 天的日志文件全部挪到当天的归档目录mkdir -p /var/log/archive/$(date %F) find /var/log/myapp -type f -mtime 30 -exec mv {} /var/log/archive/$(date %F)/ \;第一行先把归档目录建好第二行用 find 把老文件搬过去。如果省掉第一行mv直接搬到一个不存在的目录会失败所以这个mkdir -p几乎是整个操作的保底锁。5. 常见问题与避坑指南5.1 目录已存在为什么还报错mkdir最常见的报错之一就是File exists。这在交互式命令行里没什么影响但在脚本里就很烦人特别是脚本被重复执行的时候。如果一个脚本是手动运维用的第二次跑就会遇到“目录已存在”然后失败退出这体验很差。解决方案就是统一使用-p。它的好处前面说过是幂等目录在不在都能按你的预期办事。不过要小心一个行为差异如果目标路径是一个普通文件不是一个目录mkdir -p会提示cannot create directory xxx: File exists所以它并不是百分之百的静默。这背后是它只在“目标已经是目录”时才跳过如果同名文件挡路依然会报错。排查这种情况就看一眼ls -l确认是不是有一个同名普通文件删掉或改名即可。5.2 权限不足导致的创建失败权限不足的场景一般有两种。一种是你对父目录没有写权限比如试图在/usr/local下创建目录而当前用户不是 root。另一种是父目录虽然有写权限但是被某个安全模块拦截比如 SELinux 的上下文策略限制。在 CentOS、Rocky 这类系统上如果mkdir报的错看起来像权限问题但又感觉“没什么不对”可以先ls -ldZ看一下 SELinux 上下文确认是不是策略把路径卡住了。普通场景下的排查顺序是这样的# 1. 确认当前用户身份 whoami # 2. 确认父目录权限w 表示有写权限 ls -ld /parent # 3. 强行创建并看完整错误 mkdir -p /parent/newdir如果确实是因为权限不足解决办法是切换用户或用sudo。每次都用sudo提权来建目录不是好习惯但/usr/local、/opt这类系统级路径往往是管理员才能写个人使用场景下优先考虑把业务目录放在自己有完全控制权的路径下比如/home或/data下某个专属目录避免后续权限纠缠。5.3 目录名带空格、特殊字符的坑Linux 文件名里可以包含空格、换行甚至-开头但它们进入命令行后都容易被 shell 误解。如果目录名是My Documents直接mkdir My Documents会创建两个目录My和Documents这不是你想要的结果。正规做法是加引号或转义符mkdir My Documents mkdir My\ Documents我不太推荐转义符的写法因为看着费劲而且很容易漏写。嵌套多层路径时更麻烦比如mkdir -p /home/user/My Documents/2025/Jan这里整段路径用一对双引号包住最稳妥。还有一种情况是目录名以-开头比如建一个名为-data的目录直接mkdir -data会把-data当成选项去解析导致命令异常。两个办法加--分隔选项和参数或者写全路径mkdir -- -data mkdir ./-data这点在解析包含用户输入的文件名时尤其要注意写脚本时建议培养“路径变量全部加引号”的肌肉记忆。5.4 脚本里 mkdir 失败的调试技巧写 Shell 脚本时mkdir失败通常不会立刻致命而是默默返回一个非零退出码导致后续步骤在错误的状态下继续执行最后出现一个特别难查的 bug。我建议在脚本里加两个保护机制。第一个开头加set -e让任何命令返回非零就立刻退出。第二个如果某个mkdir -p的结果很重要可以显式检查mkdir -p $SOME_PATH || { echo 目录创建失败: $SOME_PATH; exit 1; }还有一个日常调试技巧是用strace去看它到底卡在哪一步系统调用上。比如strace -e mkdir,chmod mkdir -p a/b/c你可以看到它是不是先尝试创建a再创建a/b然后逐级往上。遇到权限问题时strace能直接输出EACCES (Permission denied)比猜测快得多。我遇到过一次最折腾的案例是 NFS 挂载目录上创建子目录时总是慢半拍偶尔报错。最后发现是 NFS 的缓存和权限映射问题从mkdir本身找不到原因但通过strace观察它返回的 errno 以及耗时才定位到服务端的文件系统问题。这种问题最怕的就是只看表面报错不从底层调用去深挖。6. 一路实操下来我养成的几个习惯分享几个我实际工作中一直坚持的习惯也算是对全文的补充。第一个习惯是把mkdir -p当成默认操作。除了极少数特意测试报错行为的场景我几乎不会使用不带-p的mkdir。理由很简单它能确保“最终目录存在”而不是新建一个本来就不存在的复杂路径。生产环境里省去一层判断就少一个出错的机会。第二个习惯是创建目录时顺手把权限写清楚。如果是敏感信息目录-m 700直接建如果需要共享-m 770。不嫌麻烦因为后续单独执行chmod完全能补充但一步到位能减少中间态的暴露时间尤其是在交付给外部系统时权限状态更明确。第三个习惯是结合install -d使用。刚接触 Linux 的人可能不太熟悉install命令但它其实是把mkdir -p、chown、chmod合并到一步的利器。每次需要创建一个带特定属主和权限的目录时install -d -o user -g group -m 750 /path比三行命令简洁得多脚本出错概率也低。最后不要忽略--verbose这类小参数。人眼看到输出比在脑内推理可靠脚本调试阶段mkdir -pv那几行输出能省下很多来回验证的时间。等确认稳定后再根据需要删掉-v也不迟。
返回列表