【Linux系统编程】 指令(二):一条路径是怎么定位到文件的

01 我为什么会困惑?

上一篇把"命令怎么跑起来"讲通了。这一篇回到最基础的东西:文件在哪、我怎么描述它在哪。

我一开始卡住的是这四个问题:

  1. 一个文件名叫 /home/whb/test/file.txt,为什么这么长?开头那个 / 和中间那些 /,是一回事吗?
  2. 每个目录里都有 ...这俩是谁放进去的?能删掉吗?
  3. lsls -l 的输出差了十万八千里,那一列一列到底是什么?
  4. 相对路径我总写错------它到底是相对于谁?

这四个问题的答案,都指向同一个东西:Linux 用一棵树来组织所有文件,而"路径"就是描述"怎么从树根走到那个节点"的路线。


02 先建立一个直觉

2.1 整个文件系统是一棵树

Linux 把磁盘上的所有文件和目录,组织成一棵多叉树

text 复制代码
                    /            ← 根节点,全系统唯一
        ┌───────────┼───────────┬──────────┐
      home         etc         usr        tmp
        │           │           │
   ┌────┴────┐   passwd       bin
  whb       zbc                │
   │                          ls
 ┌─┴──┬──────┐
test  temp  file.txt

有两个关键性质,记住它们,后面全通:

  • 每个节点只有一个父节点 → 所以从根往下走到任何一个节点,路线都是唯一的
  • 根节点 / 全系统只有一个 → 所以每条路线都有一个统一的起点

路径的唯一性就是这么来的。 不是为了好看,是为了让"定位一个文件"这件事没有歧义。

2.2 路径就是"从树根到目标的一条路线"

text 复制代码
/home/whb/test/file.txt
↑    ↑   ↑    ↑     ↑
根  home  whb  test  file.txt

一层一层往下走,每走一层就用一个 / 分开。就这么简单。

2.3 家目录:你一登录就被扔进去的地方

登录之后,默认会站在一个目录里。这个目录叫家目录

  • 普通用户:/home/用户名
  • root:/root(注意,不是 /home/root

为什么 root 特殊?因为 root 是装系统时就有的唯一用户,系统单独给它安排了地方;普通用户是后来加的,统一放在 /home 下面。

bash 复制代码
$ ls /home
bss  gaobo  luojie  whb  wudu

每建一个新用户,系统就在 /home 下建一个同名目录。 这就是你敲 pwd 会看到 /home/xxx 的原因。


03 正式理解

3.1 树上的两种节点

text 复制代码
非叶子节点:非空目录(下面还挂着东西)
叶子节点  :空目录,或者普通文件

有个细节值得注意:普通文件一定在叶子上 (它下面挂不了东西),但目录可以在叶子上(空目录)。

3.2 绝对路径和相对路径

这两种路径,区别只有一个问题:你的起点是哪里?

绝对路径 相对路径
起点 根目录 / 你当前所在的目录
写法 一定以 / 开头 一定不以 / 开头
特点 不随你人在哪而变 你挪个位置,它指的东西就变了
常用在 配置文件 命令行日常操作
bash 复制代码
# 绝对路径:从 / 一路写到底
[whb@bite-alicloud ~]$ cd /home/whb/test
[whb@bite-alicloud test]$ pwd
/home/whb/test

# 相对路径:从我这儿开始走
[whb@bite-alicloud test]$ cd ../temp/
[whb@bite-alicloud temp]$ pwd
/home/whb/temp

为什么配置文件里基本都用绝对路径?

因为配置文件的执行环境不确定。服务可能是开机自启的,也可能被人在任何位置手动拉起,那时它站在哪个目录完全说不准。用相对路径,同一个配置换个位置就失效了。

绝对路径不依赖"你当时在哪",这是它唯一但关键的优势。

3.3 路径里的特殊符号

符号 意思 谁能理解它
/ 分隔符(层与层之间);开头的那个是根目录 内核
. 当前目录 内核
.. 上级目录 内核
~ 当前用户的家目录 只有 shell
* 通配符,匹配任意长度(含零个)的任意字符 只有 shell
- 上一次所在的目录 只有 cd 这个命令

⚠️ 这张表最后三行是重点。 它们不是"路径语法",是别人帮你做的手脚------第 6.7 节会讲清楚谁干的。

最容易搞混的地方:/ 其实是两个东西
text 复制代码
/home/zjy/test
 ↑    ↑
 根目录  分隔符

开头的 / 是根目录(一个节点),中间的 / 是分隔符(一个标点)。 它们长得一样,身份完全不同。

一句话记:

一个路径里,第一个 / 表示"从根开始",后面的 / 表示"再下一层"。

所以 / 单独出现时,它表示的就是根目录本身:

bash 复制代码
[whb@bite-alicloud ~]$ cd /
[whb@bite-alicloud /]$ pwd
/

💡 顺便记一个跨平台的坑:Linux 用正斜杠 /,Windows 用反斜杠 \

以前的记法挺形象:"窗户(Windows)向上看,企鹅(Linux)往下看。"写代码时路径写错方向,编译器不会报错,文件就是打不开。

结尾到底要不要加 /

/home/whb/test 为例:

位置 要不要 原因
开头 必须有(除非你就在根目录) 表示从根开始
中间 必须有 分隔层级
结尾 建议不加 加了通常也能用,但容易和"这是个目录"混淆

3.4 ... 到底是谁放进去的

⭐ 这是这一节最值得搞明白的点。

bash 复制代码
[whb@bite-alicloud test]$ ls -a
.  ..  dir  file.txt

它们不是隐藏文件,是每个目录天生自带的两个目录项

  • . 指向自己
  • .. 指向父目录

所以哪怕你新建一个空目录,里面也立刻有这两个东西:

bash 复制代码
[whb@bite-alicloud test]$ tree mydir/
mydir/
0 directories, 0 files        # 用 tree 看不到,但 ls -a 能看到

它们有什么用? 三个:

  1. cd .. 能回上级,靠它
  2. 相对路径能写出来(./a.out),靠它
  3. 它让"每个目录都知道自己是谁、爸爸是谁"------这是树结构能成立的基础

🔬 一个更深的线索:这两个目录项,能从 ls -l 的"链接数"那一列看出来。

bash 复制代码
[whb@bite-alicloud test]$ ls -a -l
total 12
drwxrwxr-x  3 whb whb 4096 Jan 11 15:01 .
drwx------ 22 whb whb 4096 Jan 11 14:21 ..
drwxrwxr-x  2 whb whb 4096 Jan 11 14:22 dir
-rw-rw-r--  1 whb whb    0 Jan 11 14:22 file.txt

看第二列:

条目 链接数 为什么是这个数
.(当前目录 test) 3 = 2 + 子目录数(这里有 1 个 dir
dir(空目录) 2 空目录没有子目录,2 + 0
..(家目录 whb) 22 = 2 + 家目录下的子目录数(20 个)
file.txt(普通文件) 1 普通文件只有自己这一个名字

🔬 规律:目录的链接数 = 2 + 它下面子目录的个数。

那个 2 是固定的:

  • 1 来自自己目录里的 .
  • 1 来自它自己在父目录里的名字

每多一个子目录,就多一个 .. 指回来,所以加 1。

💡 理解这一条的好处 :以后看到某个目录链接数异常大,就知道它下面塞了很多子目录------这是不用 ls 就能粗略判断目录规模的技巧。


04 它到底是怎么工作的?

4.1 内核怎么顺着路径一层层找

🔬 你写 /home/zjy/test/file.txt,内核并不是"一下子找到"的,而是一层一层剥

text 复制代码
打开 /home/zjy/test/file.txt

1. 从根目录 / 开始(全系统唯一确定的起点)
2. 在 / 里找名为 home 的条目    → 拿到 home 的 inode
3. 在 home 里找名为 zjy 的条目   → 拿到 whb 的 inode
4. 在 whb 里找名为 test 的条目   → 拿到 test 的 inode
5. 在 test 里找名为 file.txt     → 拿到目标 inode
6. 检查权限 → 打开文件,返回 fd

每一步都是"在上一层的目录里查一个名字"。

这就解释了三件事:

  • 为什么中间任何一层不存在,报错都是 No such file or directory ------ 因为走到那一步就断了
  • 为什么目录少了 x 权限就进不去 ------ 因为"在目录里查名字"这个动作需要 x(权限那篇讲过)
  • 为什么路径越长越慢 ------ 层数越多,要查的表越多

💡 "目录"的本质是什么?就是一张表:名字 → inode 号。

你在里面加一个文件,就是往这张表里加一行;删一个文件,就是删掉一行。

4.2 相对路径是相对于谁?

⭐ 相对于当前工作目录(current working directory,简称 cwd)。

这里有个必须说清楚的点:cwd 是"每个进程各有一份"的。

  • 你所在的 shell 有一个 cwd
  • 你跑起来的每个程序,也各有一个 cwd
  • 程序启动时,它的 cwd 是从父进程继承来的(也就是继承你 shell 当时所在的位置)

这就顺手解释了一个经典现象:你在终端里 cd 到某个目录再启动程序,程序里的相对路径就是从那个目录算起的。

4.3 pwd 凭什么知道我在哪

💡 pwd = Print Working Directory,输出的就是当前 shell 的 cwd。

但这里有个细节:cwd 在内核里其实是以 inode 的形式记着的 ,不是一个字符串。要把 inode 反推成 /home/zjy/test 这样的字符串,得顺着 .. 一路爬到根,再从根往下列。

bash 复制代码
$ pwd          # -L,逻辑路径:直接用 shell 记着的 $PWD
$ pwd -P       # 物理路径:真的从 inode 爬一遍,符号链接会被解开

💡 平时这两个输出一样。但如果你 cd 进了一个软链接指向的目录,两者就会不一样------前者保留你走进去的那条"软链接路线",后者给你真实位置。

4.4 cd 为什么必须是 shell 内建的

⭐ 这一点上一篇提过,这里补齐原因。

cd 改的是"当前进程的工作目录"。

  • 如果 cd 是个外部程序,shell 就得 fork 一个子进程来跑它
  • 子进程改了自己的 cwd,但父进程(shell)的 cwd 一点没变
  • 结果就是:你 cd 完了,一回头还在原地

所以 cd 只能由 shell 自己执行。

🔬 这条规律在整个 Linux 里都成立:子进程改不了父进程的状态。

权限那篇里 su 为什么是"套一层"而不是"变身",原因也是这个。

4.5 ls 到底在读什么

💡 ls 做的事,本质上是:向内核请求"把这个目录里有哪些名字给我",然后格式化打印。

所以:

你敲的 本质
ls 读目录这张表,打印名字
ls -a 读表,包括 . .. 和以 . 开头的项
ls -l 读表,然后对每一项再查一次属性(inode 里的字段)
ls -i 读表,顺便把每项对应的 inode 号打出来

🔬 注意 -l 比裸 ls:因为它不只是读目录,还要为每一项去取 inode 属性。项一多就慢。

4.6 三个时间:atime / mtime / ctime

🔬 stat 会打出三个时间,初看很像,其实管三件不同的事:

简称 全称 什么时候变
atime Access time 读了这个文件内容
mtime Modify time 改了文件内容
ctime Change time 改了文件的属性 / 元数据(权限、所有者、大小......)

⚠️ 最容易误解的一点:ctime 不是"创建时间"。

它是"inode 状态最后一次变化的时间"。真正的创建时间叫 Birth ,而且很多文件系统压根不记录它------你看课件和参考博客里的 stat 输出,Birth: 那一行都是 -

理解这三个时间的关系,抓住一句话就行:

改内容,会连带改 mtime 和 ctime;改属性,只改 ctime。

为什么?因为:

  • 改内容 → 内容变了(mtime 变)+ inode 里的"大小 / 块数"也变了(ctime 变)
  • 改权限 → 内容没动(mtime 不变),但 inode 变了(ctime 变)

💡 这条规律在下一篇讲 touch 时会再撞上------touch -a 之后你会看到 atime 变、ctime 也跟着变,用上面这条就能解释。


05 把几个概念串起来

text 复制代码
                    /
                    │   ← 路径解析的起点,全系统唯一
        ┌───────────┼──────────┐
      home         etc        usr
        │                     │
      zjy                    bin
        │
      test  ◄──── 你的 shell 的 cwd 在这
        │
     file.txt  ◄──── 相对路径 "file.txt" 指的就是它


路径解析:/  →  home  →  zjy  →  test  →  file.txt
         每一步都是"在上一层目录里查一个名字"


同一个文件的三种写法:
  绝对路径    /home/whb/test/file.txt
  相对路径    file.txt              (因为 cwd 就在 test)
  家目录写法  ~/test/file.txt        (~ 由 shell 展开)

一句话总结

树结构决定了路径唯一,cwd 决定了相对路径从哪算起,而"查名字"这个动作是内核一层层做的。


06 实际命令

6.1 pwd

bash 复制代码
$ pwd
/home/whb/test

💡 没有常用选项(-L / -P 前面讲过)。这是最没有意外的一个命令,但它是你迷路时第一个该敲的。

6.2 cd ------ 四个最常用的写法

bash 复制代码
# 1. 回上级目录
[whb@bite-alicloud ~]$ cd ..
[whb@bite-alicloud home]$ pwd
/home

# 2. 回家目录
[whb@bite-alicloud test]$ cd ~
[whb@bite-alicloud ~]$ pwd
/home/whb

# 3. 回到上一次待过的目录
[whb@bite-alicloud ~]$ cd /
[whb@bite-alicloud /]$ cd -
/home/whb

# 4. 用绝对路径直接跳过去
[whb@bite-alicloud home]$ cd /home/whb/test

cd - 值得单独说。

它不是"退回上一级",是"回到我上一次待过的目录"。这两个完全不是一回事:

命令 去哪
cd .. 上一级目录(父目录)
cd - 上一次所在的目录(可能是任何地方)

cd - 还有个细节:它会在两个目录之间来回弹。

bash 复制代码
[whb@bite-alicloud ~]$ pwd
/home/whb
[whb@bite-alicloud ~]$ cd /
[whb@bite-alicloud /]$ cd -          # 回到 /home/whb
/home/whb
[whb@bite-alicloud ~]$ cd -          # 又跳回 /
/
[whb@bite-alicloud /]$ cd -          # 再跳回来
/home/whb

它是怎么做到的?shell 一直记着你的上一个目录(存在 $OLDPWD 里) ,所以本质上是 cd $OLDPWD,外加把目标路径打印出来。

💡 改代码时的实用场景 :你经常要在"项目目录"和"日志目录"之间反复横跳,cd - 比敲一长串 cd ../../.. 快得多。

6.3 ls 选项速查

选项 干什么 什么时候用
-a 显示所有条目,包括 . .. 和以 . 开头的隐藏项 找配置文件(.bashrc.gitignore 都是隐藏的)
-l 显示详细信息 最常用
-d 把目录当成一个整体显示,而不是列出它的内容 ls -ld /home
-i 显示 inode 号 理解硬链接、排查同名文件
-n 用数字 UID / GID 代替用户名和组名 用户名显示不出来时
-k 以 KB 为单位显示大小 看大文件
-F 每个名字后面加一个符号标明类型 快速区分目录和文件
-r 反向排序
-t 按时间排序 找最近改过的文件
-s 在名字前面输出大小 找目录下最大的文件
-R 递归列出所有子目录
-1 一行只输出一个 给别的命令消费

-F 加的那些符号是什么意思:

后缀 类型
/ 目录
* 可执行的普通文件
@ 符号链接
` `
= 套接字
选项可以连写
bash 复制代码
ls -a -l      # 分开写
ls -al        # 连写
ls -la        # 顺序无所谓

这三种完全等价。惯例是先写 -l 这类"主选项",再写修饰性的。课件里那条最长的:

bash 复制代码
[whb@bite-alicloud test]$ ls -alFn

拆开就是 -a(全都要看)+ -l(详细信息)+ -F(标类型)+ -n(数字 UID)。

实例对照
bash 复制代码
[whb@bite-alicloud test]$ ls
dir  file.txt

[whb@bite-alicloud test]$ ls -a
.  ..  dir  file.txt

[whb@bite-alicloud test]$ ls -a -l
total 12
drwxrwxr-x  3 whb whb 4096 Jan 11 15:01 .
drwx------ 22 whb whb 4096 Jan 11 14:21 ..
drwxrwxr-x  2 whb whb 4096 Jan 11 14:22 dir
-rw-rw-r--  1 whb whb    0 Jan 11 14:22 file.txt

[whb@bite-alicloud test]$ ls -a -l -F
total 12
drwxrwxr-x  3 whb whb 4096 Jan 11 15:01 ./
drwx------ 22 whb whb 4096 Jan 11 14:21 ../
drwxrwxr-x  2 whb whb 4096 Jan 11 14:22 dir/
-rw-rw-r--  1 whb whb    0 Jan 11 14:22 file.txt

[whb@bite-alicloud test]$ ls -alFn
total 12
drwxrwxr-x  3 1003 1003 4096 Jan 11 15:01 ./
drwx------ 22 1003 1003 4096 Jan 11 14:21 ../
drwxrwxr-x  2 1003 1003 4096 Jan 11 14:22 dir/
-rw-rw-r--  1 1003 1003    0 Jan 11 14:22 file.txt

对着这四条看变化,比背选项表有用得多:

  • -a. .. 冒出来了
  • -l 让每行信息量暴涨
  • -F 让目录后面多了 /
  • -nwhb 变成了 1003

⚠️ 顺便注意:-l 输出开头那一行 total 12 ,是这个目录占用的磁盘块总量(单位通常是 1KB 的块),不是文件个数,也不是总字节数。很多人第一次看到会猜错。

6.4 看懂 ls -l 的每一列

text 复制代码
-rw-rw-r--  1 whb whb    0 Jan 11 14:22 file.txt
↑↑↑ ↑↑↑ ↑↑↑ ↑  ↑   ↑     ↑      ↑         ↑
││  │   │   │  │   │     │      │         └─ 文件名
││  │   │   │  │   │     │      └─ 最后修改时间(mtime)
││  │   │   │  │   │     └─ 大小(字节)
││  │   │   │  │   └─ 所属组
││  │   │   │  └─ 所有者
││  │   │   └─ 链接数(见 3.4)
││  │   └─ 其他人的权限
││  └─ 同组的权限
│└─ 所有者的权限
└─ 文件类型

记住这张图,ls -l 就不再是天书。

6.5 stat ------ 比 ls -l 更全的属性

bash 复制代码
[whb@bite-alicloud test]$ stat newFile.txt
  File: 'newFile.txt'
  Size: 0                 Blocks: 0          IO Block: 4096   regular empty file
Device: fd01h/64769d      Inode: 1844719     Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1003/     whb)   Gid: ( 1003/     whb)
Access: 2023-01-11 15:06:45.832787572 +0800
Modify: 2023-01-11 15:06:45.832787572 +0800
Change: 2023-01-11 15:06:45.832787572 +0800
 Birth: -

逐行读:

字段 什么意思
Size 文件内容大小(字节)
Blocks 实际占了多少个 512B 的块
IO Block 文件系统的块大小(这里是 4096)
regular empty file 文件类型描述
Device 文件所在设备(十六进制 / 十进制两种写法)
Inode inode 号
Links 硬链接数
Access (0664/-rw-rw-r--) 权限,数字和字符两种写法都给了
Uid / Gid 所有者和组,括号里是数字 ID 和名字
Access / Modify / Change 三个时间(见 4.6)
Birth 创建时间,这里没记录,所以是 -

💡 statls -l 强在哪? 两个地方:

  1. 给你精确到纳秒的时间
  2. 给你 inode 号、块数、设备号 这些 ls -l 根本不显示的东西

6.6 file 和 tree

bash 复制代码
$ file test.c
test.c: C source, ASCII text

$ file /dev/pts/0
/dev/pts/0: character special (136/0)

file 是干嘛的? 它不看你文件名的后缀(test.txt 完全可以是一个可执行程序),而是真的去读文件开头那几个字节,根据"魔数"判断这是什么。

💡 这就是它比"看后缀"靠谱的原因。从别人那儿拿到一个不知道是什么的文件,file 一下比猜半天强。

bash 复制代码
$ tree path1
path1
└── path2
    └── path3
        └── path4

tree 是递归展示目录结构 ,复习时用它比 ls -R 直观得多。

💡 装法:root 直接 yum install -y tree;普通用户要 sudo yum install -y tree(权限那篇讲过为什么)。

6.7 通配符 * ------ 其实是 shell 干的

🔬 这一节是我觉得最值得记住的一个反转。

bash 复制代码
[whb@bite-alicloud test]$ cp *.txt dir

你以为 cp 收到了 *.txt 这个字符串吗?

没有。 真实过程是:

text 复制代码
1. shell 看到 *.txt
2. shell 去当前目录里翻一圈,把所有以 .txt 结尾的名字找出来
3. shell 把它们展开成一个个真实文件名,再交给 cp
4. cp 收到的其实是 "a.txt b.txt c.txt" 这样的东西
   ------ cp 从来没见过那个星号

所以"通配符"是 shell 的功能,不是命令的功能。

这一条能解释好几个现象:

  • 为什么在 C 程序里 argv 永远收不到 * ------ shell 在程序启动前就替换掉了(第 08 节展开)
  • 为什么 rm -rf * 这么危险 ------ 它不是"模糊删除",而是先展开成一长串真实文件名,再一次性全删
  • 为什么 ~ 也是同理 ------ 你写 ls ~,shell 先把它换成 /home/whbls 收到的是替换后的路径

常用写法:

bash 复制代码
ls *.txt        # 所有以 .txt 结尾的
ls mulu*        # 所有以 mulu 开头的
ls *test*       # 名字中间带 test 的

⚠️ 一个必须知道的坑:* 匹配不到以 . 开头的隐藏文件。

bash 复制代码
$ rm -rf *        # 删掉当前目录所有内容,但 .bashrc 这类隐藏文件还在

这不是 bug,是故意设计 ------防止你一个 * 就把配置全删了。隐藏文件要单独处理。


07 常见误区

误区 真相
路径里所有 / 都一样 开头那个是根目录,后面的是分隔符
. 是"隐藏文件"的意思 .当前目录ls -a 里之所以一堆,是因为文件名以 . 开头才算隐藏
cd ..cd - 差不多 .. 是父目录,-上一次待过的目录,完全不是一回事
相对路径相对于"我上次待的目录" 相对于当前工作目录(cwd),跟历史无关
ls -l 里的 total 12 是文件总数 这个目录占的磁盘块总量,不是文件个数
stat 里的 Change 是创建时间 inode 状态最后变化的时间 。创建时间是 Birth,很多文件系统不记录
*ls / rm 的功能 是 shell 的功能,在命令执行前就已经展开了
* 能匹配所有文件 匹配不到以 . 开头的隐藏文件
Linux 和 Windows 的路径斜杠通用 Linux 用 /,Windows 用 \,写代码时最常见的翻车点
~ 到处都能用 只有 shell 认它 。程序里写 fopen("~/a.txt") 是打不开的
ls -l 目录ls -ld 目录 一样 -l 列的是目录里的东西-ld 列的是目录自己
目录删掉就没了 ... 它是目录结构的一部分,删不掉------你能删的是. 开头的隐藏文件,不是这两个目录项

08 和 C/C++ 联系起来

8.1 程序里的相对路径,是从哪算起的

c 复制代码
fopen("data.txt", "r");

这个 data.txt 从哪找?从进程的当前工作目录(cwd)算起 ,而进程启动时的 cwd 是从父进程继承的------也就是你敲命令时 shell 所在的位置。

bash 复制代码
$ cd /home/whb/project
$ ./a.out                    # 这里的 "data.txt" 指 /home/whb/project/data.txt

$ cd /
$ /home/whb/project/a.out    # 同一个程序,现在 "data.txt" 指 /data.txt(大概率打不开)

💡 这就是"我明明编译好了,怎么换个目录就找不到文件"的根因。 以后遇到先想 cwd,别先怀疑代码。

8.2 ~* 不是内核认的

这一条 6.7 讲过,放到 C 里更明显:

c 复制代码
fopen("~/data.txt", "r");             // ❌ 打不开。~ 是 shell 的展开,内核不认识
fopen("/home/whb/data.txt", "r");     // ✅

同样:

c 复制代码
int main(int argc, char *argv[]) {
    // 你敲 ./a.out *.txt,argv[1] 收到的不是 "*.txt"
    // 而是 shell 已经展开好的一堆文件名
}

记住这句话:~*$变量 都是 shell 层的语法,程序永远看不到它们原本的样子。

8.3 chdir 和 getcwd

程序里也能"换目录",靠系统调用:

c 复制代码
#include <unistd.h>

chdir("/tmp");               // 改变当前进程的 cwd,对应 shell 里的 cd

char buf[4096];
getcwd(buf, sizeof(buf));    // 拿到当前 cwd 的字符串,对应 shell 里的 pwd

💡 注意 chdir 只影响当前进程自己 。你写个程序调 chdir,跑完之后你的 shell 还站在原地

------这就是 4.4 那条规律的实证:子进程改不了父进程的状态 ,也是 cd 必须内建的原因。

8.4 路径有长度上限

c 复制代码
#include <limits.h>

PATH_MAX        // Linux 上通常是 4096

路径不是能无限长的。写代码拼接路径时别用固定大小的小数组,容易溢出------用 snprintf 并检查它的返回值。


09 最后真正记住什么?

text 复制代码
【定位一个文件,靠的是四个概念】

    树(结构)          路径(描述)          cwd(起点)         内核(执行)
        │                   │                    │                   │
        │ 每个节点只有       │ 绝对:从 / 开始     │ 每个进程各一份     │ 一层层查名字
        │ 一个父节点         │ 相对:从 cwd 开始   │ 从父进程继承       │ 每层都查权限
        │                   │                    │                   │
        └───────────────────┴────────────────────┴───────────────────┘
                                      │
                                      ▼
                            路径具有唯一性

这部分读完,脑子里留下四个模型就够了:

  1. 文件系统是一棵树 ,每个节点只有一个父节点,所以路径能唯一定位。... 是每个目录天生自带的两个目录项,也是树结构能成立的基础------它们能从 ls -l 的链接数那一列被验证。
  2. 绝对路径和相对路径的区别只有一个问题:起点是 / 还是 cwd。 配置文件用绝对路径,是因为它不能依赖"你当时在哪"。
  3. cwd 是每个进程各一份、从父进程继承的。 这就是 cd 必须内建、程序换目录不影响 shell、程序换个位置就跑不起来的原因。
  4. ~*$变量 都是 shell 干的活,不是内核的语法。程序永远看不到它们原本的样子。

下一篇 :创建、删除、复制、移动文件,以及把文件内容打出来看(touch / mkdir / rm / rmdir / cp / mv / cat / more / less / head / tail)。

相关推荐
人工智能培训1 小时前
大语言模型:从语言理解到通用智能的跃迁
linux·服务器·前端·人工智能
顶点多余1 小时前
9.20 知识点查漏补缺
linux·面试·职场和发展
库玛西1 小时前
数据结构与算法之美:树、森林与二叉树全解析
c语言·数据结构·笔记·考研·算法·学习方法
木井巳1 小时前
【记忆化搜索】最长递增子序列
java·算法·leetcode·深度优先·剪枝·推荐算法
东方护航数据恢复(深圳)1 小时前
本地小算力设备数据恢复经典案例实操全解_东方护航数据恢复深圳店
大数据·服务器·算法·ai·gpu算力
小贺儿开发1 小时前
Unity 结合百度AI开放平台 手写文字识别
人工智能·科技·学习·unity·云服务·文字识别·手写文字
传奇开心果编程1 小时前
【SwiftUI入门练中学】第1课 从零开始
学习·ui·ios·swiftui·swift
Omics Pro1 小时前
上海AI Lab孙思琦×高张阳:虚拟细胞代码库智能体
数据库·人工智能·算法·机器学习·自然语言处理
Y幽谷客2 小时前
图像识别入门习题整理
算法