ARTICLE DETAIL

资讯详情

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

Linux cd指令详解:绝对路径、相对路径与当前工作目录

Linux cd指令详解:绝对路径、相对路径与当前工作目录 刚接触Linux时我被一个问题坑了很久忘记当前在哪就不知道该往哪走。很多新手盯着终端发蒙第一道坎就是命令行前面那串路径提示符。其实Linux所有文件操作都默认发生在某个具体目录里cd指令切换的正是这个位置而相对路径和绝对路径则决定你怎么描述目标地点。这篇文章我会把这三个概念从原理讲到实操不仅说清楚命令怎么敲更把背后的文件系统逻辑、执行场景和那些文档里不会写的坑一起讲透。适合刚入门的Linux学习者也适合写脚本时总在路径上翻车的开发者和运维。1. 先把当前目录这个概念彻底搞清楚1.1 为什么总要知道自己在哪Linux文件系统的结构是一棵倒挂的树根目录是/sys下一切文件、目录、设备都挂在这棵树上。你每时每刻都站在树的某个节点上这个节点就叫当前工作目录Working Directory。命令行里几乎所有操作都默认带着这个位置属性ls # 列出当前目录下的文件 rm temp.log # 删除当前目录下的temp.log cat README # 查看当前目录下的README连./deploy.sh这种写法本质也是一个相对路径——从当前位置出发去寻找那个脚本。所以我在哪不只是一个心理安慰它直接决定了你敲下去的命令会作用在哪儿。我自己每次SSH登录到服务器第一件事都是敲pwd确认位置这个习惯救过我很多次。1.2 查看当前位置的几种方式最直接的方式是pwd命令全称 print working directory$ pwd /home/zhang除此之外Shell把当前目录存在环境变量PWD里所以echo $PWD也能看到。还有一个更常用的观察入口就是命令提示符PS1[zhangubuntu ~]$这里的~在提示符里表示家目录它其实是对/home/zhang的缩写显示。Ubuntu默认提示符长这样CentOS默认通常也是[roothost ~]#。看到~就说明你在家目录里看到/etc/nginx之类就说明你在其它目录。不少新手容易混淆~和/前者是家目录快捷写法后者才是文件系统的根。这两个符号在后面的路径展开中逻辑完全不同务必区分。2. 绝对路径从根目录出发全局唯一的地址2.1 根目录和绝对路径的构成逻辑绝对路径以/开头描述的是从根目录到目标位置的完整链路。比如/home/zhang/project/web/index.html这条路径从根目录/出发依次经过home、zhang、project、web最后指向index.html。只要这个文件存在无论你当前站在哪里这条路径都能唯一定位到它像快递地址从国家写到门牌号不会因为寄件人位置不同而改变。Linux使用这样的单根树形结构是继承了UNIX的传统——所有设备、文件、挂载点都统一放在一棵树上。U盘插进来会被挂载到/media/用户名/xxx这类目录而不是像Windows那样出现一个D盘。对程序来说路径空间是统一的这大大简化了文件寻址的逻辑。2.2 绝对路径适合用在哪些场景绝对路径最大的优点是稳定它不依赖任何上下文。所以以下场景几乎必须使用绝对路径系统服务的配置文件比如/etc/nginx/nginx.conf里指定的日志路径、证书路径。crontab定时任务里要访问的文件或要执行的命令。systemd unit文件中ExecStart、WorkingDirectory的配置。需要在多个深层目录之间来回切换时比如cd /var/log/nginx和cd /usr/local/src用绝对路径不容易把自己绕晕。面试时如果被问到绝对路径和相对路径的区别一句话概括就是绝对路径以根目录为起点完整、稳定、不依赖当前位置相对路径以当前目录为起点灵活、简短、但依赖上下文。这个答案基本能拿满分。有不少人在写脚本时图省事用相对路径结果定时任务一跑就找不到文件这就是没分清稳定地址和临时地址的区别。系统级任务、长期运行的守护进程、跨用户共享的配置都应该优先用绝对路径。3. 相对路径以当前位置为锚点的灵活导航3.1.和..两个隐形的路径记号相对路径不以/开头它是从当前目录出发来描述位置的。核心记号有两个.代表当前目录..代表上一级目录。每个目录里都存在这两个隐藏条目用ls -a就能看到$ ls -a /home/zhang/project . .. bin conf logs.和..是文件系统自带的固定条目。它们的存在让这里和上面这两个概念变成了可以书写、可以引用的路径。举个例子cd ./backup # 进入当前目录下的backup等价于 cd backup cd .. # 回到上一级目录 cd ../.. # 回到上两级目录 cd ../backup # 先回到上一级再进入上一级下面的backup很多老手习惯在脚本里把当前目录下的脚本写成./run.sh不是因为run.sh和run.sh有什么不同而是为了显式表达我就是要运行当前目录下的这个文件。因为Shell查找可执行文件时默认只在PATH环境变量指定的目录里找不会在当前目录找。假如你把一个脚本放在当前目录直接敲脚本名大概率是command not found必须写成./run.sh这种相对路径形式才能命中。3.2 相对路径的灵活性和使用边界相对路径的优势是灵活性。项目内部的文件互相引用时只要整个项目整体搬迁相对关系保持不变路径就依然有效。比如一个项目目录长这样project/ ├── bin/ │ └── run.sh ├── conf/ │ └── app.conf └── logs/你在project目录下时进入conf只需要敲cd conf查看配置就是conf/app.conf。这种写法比每次敲一长串绝对路径高效得多。但相对的代价是依赖上下文。同样一条命令cd ../backup你在/home/zhang下执行目的地是/home/backup你在/var/www下执行目的地就变成了/var/backup。所以相对路径适合人肉操作和项目内导航不适合写进跨环境、跨平台运行的固定任务里。我自己交互式操作的习惯是先cd到项目根目录再统一用相对路径访问子目录。这样命令短、可读性好、也不容易打错。4. cd指令的真正用法与那些不守规矩的坑4.1 cd的几个标准形态cd是Shell内建命令不是外部程序因为它必须改变当前Shell进程的工作目录。如果用外部程序实现它只能在子进程里切换目录切完就没了起不到作用。cd的常用形态下面这个表基本覆盖了命令作用cd /etc/nginx用绝对路径进入指定目录cd nginx进入当前目录下的nginxcd ..回到上一级目录cd ~进入当前用户的家目录cd不带参数等价于cd ~cd -回到上一次所在的目录cd ../backup先回上一级再进入backupcd ~otheruser进入指定用户的家目录有权限时一段操作示例$ pwd /home/zhang $ cd /var/log $ cd - # 回到 /home/zhang $ cd ~ # 还是 /home/zhang4.2 cd - 背后的OLDPWD机制cd -这个命令非常实用但不少人用了很久Linux都没发现它。它的作用是回到上一个工作目录。实现原理是Shell维护了一个环境变量OLDPWD每次cd成功后Shell把旧路径存进OLDPWD然后更新PWD。所以cd - # 等价于 cd $OLDPWD echo $OLDPWD # 查看上一次的目录排查线上问题时这个命令特别方便比如你在/var/log/nginx下翻完日志一条cd -就能回到之前的目录不用再敲一长串路径。反复执行cd -就等于在最近的两个目录之间来回跳效率很高。4.3 目录名含空格、特殊字符的处理Linux目录名允许包含空格、中文甚至通配符这给cd带来了一些麻烦。假设你有一个目录叫My Documentscd My Documents # 错误Shell把它当成两个参数 cd My Documents # 正确加双引号 cd My\ Documents # 正确反斜杠转义空格最省心的办法还是Tab补全。输入cd My后按TabShell会自动补全并处理好空格转义。我几乎不手敲长路径基本都是cd加几个首字母然后Tab又快又不会错。还有一种目录名以-开头的情况比如-abc。执行cd -abc时Shell会把-abc当成选项解析直接报错。解决办法是在前面加./cd ./-abc提示遇到任何目录名包含空格、特殊符号、以横线开头的情况Tab补全都是最可靠的工具。它不只是帮你少打字更重要的是自动完成转义。4.4 CDPATH让cd行为变奇怪的隐藏变量默认情况下cd只会在当前目录里查找目标。但如果你设置了环境变量CDPATHShell会按照CDPATH里列出的路径依次搜索目标目录。比如export CDPATH:/var/log设置之后不管你在哪个目录敲cd nginx都可能直接跳到/var/log/nginx而不是当前目录下的nginx。这个行为很容易让初学者以为cd坏了实际上是CDPATH在起作用。排查方法很简单echo $CDPATH如果输出了一串路径把它清掉unset CDPATH我不建议在配置文件里主动设置CDPATH尤其是新手。它虽然能带来一点快捷方式式的便利但让路径行为变得难以预测在脚本里更是隐患。4.5 cd失败后的连锁反应交互式Shell里如果你cd到一个不存在的目录屏幕上会立刻显示No such file or directory你马上就知道出错了。但在脚本里情况完全不一样#!/bin/bash cd /non/exist/path rm -rf ./*这段脚本里cd虽然失败了但Shell不会停下来rm -rf ./*依然会执行而且是在当前的工作目录下执行。如果这个脚本是在某个重要的项目目录里被手动执行的后果不堪设想。我自己就见过一个同事在部署脚本里写rm -rf ./data因为工作目录不对把另一个项目的data目录删了好在有备份。正确的写法是把cd和后续命令绑定或者显式判断cd /some/path || { echo cd failed; exit 1; } # 或者 cd /some/path ./deploy.sh这条经验适用于所有脚本场景cd之后要么马上检查结果要么用 串联永远不要假设cd一定成功。5. 脚本、定时任务与软链接场景下的路径经验5.1 脚本里相对路径为什么会失灵交互式Shell里你站在某个目录下执行脚本脚本内部的相对路径参照的是你的当前目录而不是脚本所在目录。更麻烦的是自动化场景crontab执行任务时工作目录通常是用户的家目录和脚本所在目录不一定有关系。systemd service里如果不显式设置WorkingDirectory工作目录可能是根目录/。CI/CD流水线里agent执行脚本的工作目录取决于构建工具配置和本地项目结构往往不一致。所以脚本内部如果写相对路径很容易出现手动执行没问题一跑定时任务就找不到文件的诡异现象。解决思路是脚本开头先明确自己位于哪个目录再用相对路径组织后续操作。5.2 稳定获取脚本所在目录的写法下面这段是Shell脚本里很经典的固定写法SCRIPT_DIR$(cd $(dirname $0) pwd) cd $SCRIPT_DIR拆开看$0是脚本被调用时的路径可能是相对路径也可能是绝对路径。dirname $0取出脚本所在的目录部分。cd到那个目录再用pwd拿到绝对路径。整条命令用连接cd成功才执行pwd避免拿到错误结果。如果脚本可能被软链接安装到/usr/local/bin这类目录还需要先解析软链接指向的真实位置SCRIPT_DIR$(cd $(dirname $(readlink -f $0)) pwd)readlink -f会跟随软链接拿到脚本文件的真实路径再取目录。这种方法在编写命令行工具时非常实用能保证无论脚本被链接到哪都能找到它真正的家。5.3 软链接目录里的路径差异Linux里还有一个容易踩的路径细节软链接目录。假设/var/data是一个软链接真实指向/srv/storage/datacd /var/data pwd # 输出 /var/data pwd -P # 输出 /srv/storage/datapwd默认显示逻辑路径你进入时用的路径pwd -P显示物理路径软链接解析后的真实路径。对应的cd -P /var/data会直接进入真实物理目录。这个差异平时不显眼但遇到磁盘占用排查、find、du这类工具时就容易困惑。比如你执行du -sh .和du -sh /var/data有时候结果差异很大就和软链接目录的遍历行为有关。知道有-P和-L这两个方向遇到诡异路径问题时多一个排查思路能省不少时间。5.4 路径判断的小技巧最后分享几个配合cd使用的快速判断方法[ -d $DIR ] cd $DIR # 目录存在才进入 [ -f $FILE ] echo 存在 # 判断文件是否存在 [ ! -d $DIR ] mkdir -p $DIR # 目录不存在则创建写脚本时在cd之前先判断目标目录是否真的存在比裸写一条cd要稳妥得多。这个习惯配合上文的|| exit 1写法基本能帮你避开大多数路径相关的事故。老实说cd和路径是Linux里再基础不过的内容但几乎所有复杂的运维问题最后排查到底都可能绕回这两个词。很多部署失败、脚本不执行、服务起不来的故障根子不是程序逻辑而是路径基准错了。希望这篇内容能帮你把这块基础打牢少踩一些我踩过的坑。
返回列表