1. 先搞清楚"指定目录"到底该怎么指:路径选择的底层逻辑
很多人第一次搜"Linux怎么创建指定目录并进入",其实不是不会敲mkdir和cd这两个命令,而是栽在"指定"这两个字上——到底用/home/user/project这种一长串路径,还是直接用project?为什么有时候带了完整路径反而报错?这背后是Linux路径系统的基本规则,搞不明白就只能靠死记硬背,换个目录又懵了。
1.1 永远先回答三个问题:我在哪、我要去哪、怎么过去最稳
在Linux里敲任何路径相关的命令,本质都是在和"当前工作目录"对话。打开终端后,shell默认停在一个位置上,这个位置通常是你登录用户的家目录,也就是~。想确认自己在哪,用pwd(print working directory):
bash复制pwd
# 输出类似:/home/zhang
搞清楚当前所在位置之后,路径就分成了两种写法:
- 绝对路径:从根目录
/开始写全,比如/home/zhang/project。不管当前在哪,这个路径指向的位置都是确定的,不依赖环境。 - 相对路径:从当前位置开始描述,比如
project、../docs、./src。同样的写法,在不同的当前目录下含义完全不同。
我见过不少初学者在这上面翻车——明明在/home/zhang下创建了一个project目录,隔几天在/tmp下执行cd project,系统直接告诉他"没有这个目录",然后他就开始怀疑人生。这里要说清楚:相对路径是跟当前目录绑定的,换了个位置,同样的路径写法就不再指向原来的东西。
另外还有两个常用的路径符号,必须刻进脑子里:
.表示当前目录,比如./script.sh就是执行当前目录下的脚本;..表示上一级目录,cd ..回到上一层,cd ../..往上跳两层。
实操建议是:人肉操作时用相对路径,因为省事;写脚本、写自动化任务时用绝对路径,因为可复现。我自己写部署脚本时有个习惯——脚本开头先cd "$(dirname "$0")"把工作目录切到脚本自身所在位置,后面所有相对路径就有了确定的基准,不会因为调度方式不同而跑偏。
1.2 关于家目录的"快捷通道":~ 和 /home/用户名
家目录在Linux里有个专门符号~,等价于当前用户的home目录。比如你登录用户是zhang,那么~就是/home/zhang。这个符号最大的价值在于:你不需要每次敲完整路径,也不用去记当前用户到底是谁。
bash复制cd ~ # 回到家目录,等价于 cd /home/zhang
cd ~/project # 等价于 cd /home/zhang/project
还有个冷知识:cd不带任何参数,也是回~。所以cd和cd ~效果一样。这算是shell给你留的快捷键,用了几年Linux的人反而容易忘掉。
"指定目录"这四个字,本质上就是在绝对路径和相对路径之间做选择。理解了上面的规则,下面再看mkdir和cd的细节,就会发现其实都是围绕这套路径逻辑展开的。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. mkdir创建目录:从基础语法到没人细讲的参数细节
mkdir是"make directory"的缩写,用法本身不复杂,但很多教程只讲了个皮毛。实际场景里,大多数人真正需要的是-p这个参数——它解决的痛点是"多级目录一次创建"。只教基础语法不教-p,等于让新手在"必须先建父目录才能建子目录"这件事上反复碰壁。
2.1 mkdir最完整的功能拆解:-p、-m、-v各自解决了什么问题
先看基础语法:
bash复制mkdir 目录名
mkdir 目录名1 目录名2 目录名3 # 一次创建多个目录
一次创建多个目录时,它们之间是并列关系,都在当前目录下生成。比如:
bash复制mkdir logs backup temp
这会在当前位置一次性创建三个目录。
接下来是重头戏-p。它的学名叫--parents,意思是"自动创建父目录"。看个对比:
bash复制mkdir /data/backup/logs
# 如果 /data 或 /data/backup 不存在,直接报错:No such file or directory
mkdir -p /data/backup/logs
# 不管中间缺了多少层,一条命令全部建出来,不报错
-p还有一个容易被忽视的隐藏价值:目录已经存在时,加上-p不会报错,不加反而会提示File exists。这就让-p变成了一种"幂等操作"——不管目标目录存不存在,执行结果都符合预期。这在写自动化脚本和CI/CD流水线时是刚需:脚本跑第二遍、第三遍,不会因为目录已存在而中断。
-m参数用来直接指定权限,一步到位:
bash复制mkdir -m 700 private_dir
# 创建目录的同时设置权限为 rwx------,只有自己可读可写可进入
如果不带-m,目录权限取决于umask的默认值,通常是755或750。需要受限权限的目录,用-m会省掉后面单独执行chmod这一步。
-v参数会在每次创建成功后打印一行提示,适合在脚本里留日志用的场景:
bash复制mkdir -vp /app/{bin,conf,logs}
mkdir: created directory '/app'
mkdir: created directory '/app/bin'
mkdir: created directory '/app/conf'
mkdir: created directory '/app/logs'
2.2 一次建多级多目录的"花括号展开"技巧
-p参数配合shell的花括号展开(brace expansion),可以一行命令建立一整棵目录树。花括号展开是shell本身提供的功能,会在命令执行前把{a,b,c}这种写法展开成多个参数。
bash复制mkdir -p src/{main,test}/{java,resources}
这条命令执行后,会生成以下目录结构:
text复制src/
├── main/
│ ├── java/
│ └── resources/
└── test/
├── java/
└── resources/
一次性六层目录全部建好。这种写法在初始化项目骨架时特别实用。我当年带实习生,让他们手写八个mkdir命令建目录,后来改成一行花括号展开,输出的目录结构还更整齐——命令简洁不是目的,减少出错点才是。
2.3 目录名里带空格和特殊字符:引号与转义
Linux目录名理论上可以包含空格、中文、甚至换行,但这是在给自己挖坑。最规范的做法是从一开始就不要用空格分隔目录里的不同单词,而是用下划线或者连字符,比如my_project而不是my project。
如果实在遇到了带空格的目录名(比如某Windows系统传过来的文件夹),创建和进入时都要用引号包起来:
bash复制mkdir "my project"
cd "my project"
或者用反斜杠转义空格:
bash复制mkdir my\ project
cd my\ project
一个更省心的办法是依赖Tab键自动补全:输入目录名的前半部分后按一下Tab,shell会自动把后续内容补全并处理好空格转义,根本不用手动加引号。这在路径很长、名字很怪时是效率神器,强烈建议养成习惯。
3. cd进入目录:五种行为模式与真实使用习惯
cd(change directory)是Linux里使用频率最高的命令之一,但它的几个行为细节很多人并没有完整掌握。这些细节一旦理解到位,效率提升是立竿见影的。
3.1 cd的快捷方式:不带参数、cd ~、cd -、cd ..
列一张速查表,把cd的常见形态整理清楚:
| 命令 | 行为 | 典型场景 |
|---|---|---|
cd |
回到当前用户家目录 | 操作完一堆目录后"回家" |
cd ~ |
同上,等价于cd /home/当前用户 |
显式表达回归家目录 |
cd ~zhang |
进入指定用户的家目录 | 切换用户场景下访问其他用户的home(有权限时) |
cd - |
回到"上一个所在目录" | 在两个目录之间来回切换 |
cd .. |
回到上一级目录 | 一层层往回退 |
cd ../.. |
上跳两级 | 快速回到项目根目录附近 |
cd / |
跳到根目录 | 需要从全局视角浏览文件系统时 |
cd - 是个特别有意思的命令,它依赖shell记住的"上一个工作目录"(OLDPWD),所以不需要你手动记录之前在哪。比如你在/home/zhang/project下执行了cd /etc/nginx,再敲cd -就会直接跳回/home/zhang/project。连续执行两次cd -,会在两个目录之间反复横跳——这在对比两个目录里的文件时非常好用。
3.2 一个很多人忽略的细节:符号链接下的路径认知差异
Linux里有个经典困惑:从一个软链接(符号链接)目录执行cd ..,到底去了哪里?很多人以为会跳到软链接指向目录的上一级,但实际行为取决于shell对PWD的处理。
举个例子。假设真实路径/data/wwwroot/site,你给它在/home/zhang/下建了个快捷方式:
bash复制ln -s /data/wwwroot/site /home/zhang/site_link
cd /home/zhang/site_link
pwd
# 默认输出:/home/zhang/site_link
此时你在这个软链接目录里执行cd ..,会进入/home/zhang,而不是/data/wwwroot。因为shell默认把软链接当作普通路径来跟踪——它记住的是你"怎么走过来的",而不是"真正的物理位置"。
如果你希望shell始终显示物理真实路径,可以用pwd -P查看,或者用cd -P强制切到物理路径:
bash复制pwd -P # 显示真实物理路径
cd -P /home/zhang/site_link # 切到物理路径 /data/wwwroot/site
坦白说,日常工作里大部分人不需要较真这个区别,但一旦涉及脚本里拼接路径、备份工具对路径去重,这个坑就会冒出来。建议遇到"路径明明存在但脚本行为怪异"的时候,先用pwd -P看看自己到底站在哪。
3.3 为什么"脚本里cd了但没生效":子shell机制
这是新手问得最多的一个问题:写了个脚本,开头cd /data/project,然后在里面执行了后面一堆命令,最后手动回到终端一看,当前目录还是原来的地方。或者脚本里明明cd进去了,但脚本后面的某个环节报"目录不存在"。
问题的根源是子shell(subshell)机制。当你在终端里执行bash script.sh时,系统会启动一个全新的shell进程来运行这个脚本,这个新进程的工作目录变化不会影响父进程——也就是你当前终端的工作目录。脚本里的cd只改变了脚本自己那个进程的"当前位置",脚本跑完进程退出,一切还原。
想要脚本里的cd影响当前shell,有几种方法:
- 用
source或.执行脚本:source script.sh,让脚本在当前shell进程中跑,cd会保留下来; - 把目录切换放进函数里(后面第4节会细讲);
- 把
cd和后续依赖它的命令写在同一个脚本内,保证"切换"和"使用"发生在同一个进程里。
bash复制# 下面这种写法在脚本内部是安全的
#!/bin/bash
cd /data/project
mkdir -p logs
touch logs/run.log
这个脚本每次执行都在自己的进程里完成切换和创建,不会影响外部终端,但脚本内部的行为完全正常。理解这个机制后,你就不会再被"cd不生效"这种问题卡住。
4. 把"创建指定目录并进入"做成一条命令:三种实用姿势
回到标题本身:"创建指定目录并进入"。分开做是两步,但实际使用中,这两步几乎永远连在一起——建完目录、立刻进去开始干活。能不能一步到位?当然可以,而且有不止一种做法,各有利弊。
4.1 用&&串联:最直接的组合与失败语义
最简单的方式是用&&把两个命令串起来:
bash复制mkdir -p project && cd project
这里有个关键设计:必须用&&,不要用分号;。因为&&的意思是"只有前面的命令成功了,才执行后面的命令";分号则是"不管前面成没成功,后面的照常执行"。如果用分号:
bash复制mkdir project; cd project
一旦mkdir因为权限不足或目录名非法而失败,cd依然会执行,接下来你会看到两个报错叠在一起,而且搞不清楚到底哪一步出了问题。&&的失败语义能保证"创建失败就停在原地",错误处理更干净。
这条命令还有个变体:先创建再进入,同时用花括号展开创建多级目录:
bash复制mkdir -p src/{main,test}/java && cd src/main/java
一条命令完成"建目录树+进入核心目录",在初始化项目时配合pwd确认位置,体验非常顺畅。
4.2 把mcd函数写进shell配置:一条命令随身带
mkdir dir && cd dir敲多了之后,你会发现这七个键打起来还是很累。更优雅的方案是自定义一个shell函数,把它写进~/.bashrc或~/.zshrc:
bash复制mcd() {
mkdir -p "$1" && cd "$1"
}
保存后执行source ~/.bashrc让配置生效。之后你只需要敲:
bash复制mcd /data/project
函数内部先创建目录(-p保证了多级目录也能一次建出来),创建成功就切换进去。这里用双引号包住$1是为了兼容目录名带空格的情况——函数接收的第一个参数原样传给mkdir,带空格也不用担心被拆成多个参数。
如果你想让这个函数更"健壮",还可以加个容错逻辑:没有传参数时给出用法提示。这在写给别人用的脚本里是加分的做法,自己用其实不传参的情况很少。
我自己的~/.bashrc里还存了好几个类似的小函数,比如跳去项目目录再加载环境变量的goproj函数。把高频操作封装成函数,是Linux从"会用"到"用得舒服"的一个明显分水岭,建议每个人都动手维护一个自己的函数库。
4.3 从mkdir到CI/CD:基础命令在自动化流水线里的真实角色
搜索热词里有个词条很能说明问题:gitlab ci/cd中docker镜像构建与自动化部署实践。不少人在CI/CD的流水线脚本里被mkdir和cd坑过,原因恰恰是第3.3节讲的子shell机制——.gitlab-ci.yml里每个script行本质上都是在一个独立的shell环境中执行的,前一行里cd了,后一行的当前目录不会继承。
这种场景下的正确做法,是把需要在同一个目录里完成的动作合并到一行,或者用before_script配合变量来传递路径:
yaml复制build-job:
before_script:
- mkdir -p "$CI_PROJECT_DIR/artifacts"
script:
- cd "$CI_PROJECT_DIR/artifacts"
- echo "build start" > output.log
或者推荐的做法:每一步都显式指定完整路径,不依赖cd的"残留效果":
yaml复制script:
- mkdir -p "$CI_PROJECT_DIR/artifacts/logs"
- echo "build start" > "$CI_PROJECT_DIR/artifacts/logs/output.log"
说穿了一点都不复杂:**在自动化环境里,相对路径和cd的"状态感"是不可靠的,你唯一可以信任的是显式的绝对路径和幂等的mkdir -p。**这跟前面手敲命令时"用相对路径省事"的原则并不矛盾——人和机器的容错模型不一样。
另外顺带一提,Dockerfile里也有类似的"目录切换"问题,不过它用的是WORKDIR指令,不是cd:
dockerfile复制FROM ubuntu:22.04
WORKDIR /app
RUN mkdir -p /app/logs && echo "ready" > /app/logs/ready.txt
理解了mkdir -p和cd在普通shell里的行为,再看Dockerfile、CI脚本里的对应写法,你会发现基础命令的思维方式是通用的。
5. 从"命令报错"看排查思路:五个高频翻车现场
新手学mkdir和cd时最容易遇到的坑就那几个,但每个坑背后的排查思路其实是通用的。这一节我把高频翻车现场串一遍,每个都给判断方法和修复手段,你在自己的机器上遇到类似问题时,可以照着排查。
5.1 No such file or directory:父目录不存在的连锁反应
bash复制mkdir /tmp/a/b/c
# 输出:mkdir: cannot create directory '/tmp/a/b/c': No such file or directory
这不是因为你没权限创建c,而是因为a或b不存在,系统找不到目的地。首次接触这个报错的人很容易误判成"权限问题",其实是路径缺失。
解决方式就是加上-p:
bash复制mkdir -p /tmp/a/b/c
-p会递归地把/tmp/a、/tmp/a/b、/tmp/a/b/c全部创建出来。同时注意:/tmp本身存在,所以它不会被重建,-p对已存在的目录不会报错、不会覆盖。
5.2 Permission denied:权限不足的判断方法
创建目录时报Permission denied,意味着当前用户在你试图写入的位置没有写权限。常见于:
- 直接在根目录
/下创建目录; - 往别人的家目录或系统目录(如
/etc、/usr)里写入。
判断方法是一看位置、二看权限:
bash复制ls -ld / # 看根目录权限,通常 drwxr-xr-x,只有 root 能写
ls -ld /home/zhang # 看自己家目录权限
解决方式:
- 如果是系统级目录,确实需要创建,用
sudo mkdir -p /opt/myapp; - 如果是自己的项目目录,应该放在
~/或者/home/当前用户下,而不是直接往系统区塞东西; - 如果是多人服务器,用
sudo mkdir后记得改属主:sudo chown -R 用户名:用户组 /opt/myapp,否则后续该用户还是没权限写入。
这里分享一个我自己踩过的坑:早年在一台服务器上创建/data目录时用了sudo mkdir /data,忘了改属主,后续所有往/data里写文件的脚本全都报权限不足。排查了半天最后发现根因就是创建目录时少了chown这一下。权限问题的排查顺序永远是:先确认当前用户是谁,再确认目标目录的属主和权限位,最后才决定要不要sudo。
5.3 目录创建成功但cd不进:目录名引起的错觉
有一种很隐蔽的情况:mkdir执行成功了,但cd进不去,系统提示No such file or directory。这种大多出在目录名本身,比如名字里带着看不见的多余字符,或者录入时的空格和实际创建的不一致。
排查方法:
bash复制ls -b # 用 -b 参数显示转义字符,能看到空格显示为 \space,特殊字符也能暴露
ls -l # 看目录是否有可执行(x)权限,没有x权限就无法进入
之前提过Tab补全,在这类问题上就是最佳实践——既能避免手输空格,也能确认当前目录下到底有什么。
另外有个生活化的类比:目录的"进入权限"其实相当于一把门禁钥匙。ls -ld directory的第一个字段如果是dr-xr-xr-x,表示目录所有人只有读和执行权限、没有写权限,你进得去但建不了新文件;如果是drw-r--r--,连cd都会失败,因为缺少执行权限。遇到"明明存在但进不去",检查一下目录权限位,比换着法子敲路径更有效。
5.4 bash: cd: xxx: Not a directory:把文件当成目录用
这个报错出现的原因很直白:你试图cd的对象不是目录,而是一个普通文件。
bash复制touch a.txt
cd a.txt
# 输出:bash: cd: a.txt: Not a directory
确认对象类型用file或ls -l:
bash复制file a.txt
ls -l a.txt # 开头如果是 - 而不是 d,就是普通文件
还有一个变体:路径中间的某个部分不是目录。比如你有一个文件abc,然后执行cd abc/def,系统会报同样的错。处理方式很直接——不要在文件底下继续找子目录,回到上一级重新审视路径结构。
5.5 能让"经验"真正起到作用的是组合打法
最后分享一个我日常工作里非常喜欢用的组合技巧。它的核心要素就是前面讲到的mkdir -p加shell的$_变量(代表上一条命令的最后一个参数):
bash复制mkdir -p logs/$(date +%Y%m%d) && cd "$_"
拆开解释:
logs/$(date +%Y%m%d)会展开成类似logs/20250301这种按日期命名的目录;mkdir -p负责把它创建出来;cd "$_"中的$_自动展开为上一条命令的最后一个参数,也就是刚建好的那个日期目录。
于是"创建按日期归档的目录并进入"就变成了一条命令,不需要重复输入两遍路径。配合alias还能做成一键归档:
bash复制alias today='mkdir -p logs/$(date +%Y%m%d) && cd "$_"'
从这个角度看,"Linux怎么创建指定目录并进入"这个问题虽然基础,但它牵出来的是一整套路径认知、参数语义、进程模型和错误排查思路。把这几个点吃透,后面在脚本、容器、CI/CD里遇见的那点路径问题,就都属于"见过的坑"了。
在我自己带人的经历里,能把cd -、$_、mkdir -p这种小细节用得顺手的人,写自动化脚本的出错率确实明显低。基础命令不是背会就完事,而是要通过高频使用变成肌肉记忆。多折腾几次,多踩几个小坑,你对Linux的路径体系、权限体系和进程模型的理解,会比看十遍教程都管用。
