realpath 命令详解与参数实测(Ubuntu 22.04)

GNU realpath 参数实测:默认规范化、-e/-m/-s/-P/-L/-q/-z 与 --relative-to 相对路径,及与 readlink -f 的等价差异,Ubuntu 22.04 实测。

Linux命令Linux系统UbuntuUbuntu 22.04命令行文件管理2026/10/15

realpath 命令详解与参数实测(Ubuntu 22.04)

目标:全面掌握 GNU realpath 的每一个参数——默认规范化、-e/-m 存在性约束、-s 不展开软链、-P/-L 物理与逻辑解析、-q 静默、-z NUL 结尾、--relative-to/--relative-base 相对路径输出,以及与 readlink -f 的等价与差异,全部命令与回显已在 Ubuntu 22.04(GNU coreutils 8.32)实测通过。

一、环境信息

本篇所有命令与回显均来自同一台 Ubuntu 22.04 服务器的实测,演示数据统一放在 /root/demo/realpath/ 下,读者在任意 Ubuntu 22.04 机器上按相同步骤均可复现。

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64)
  • realpath 版本:GNU coreutils 8.32(realpath --version 实测)
  • realpath 属于 coreutils 基础工具集,Ubuntu 22.04 默认预装,无需额外安装
  • 演示目录:/root/demo/realpath/
  • 测试数据:real/sub/file.txt(真实文件)、deepdir/sub/(真实子目录,供 -P/-L 实验)、绝对软链 abs.lnk、相对软链 rel.lnk、悬空软链 dangling.lnk、指向深层目录的软链 t.lnk

二、命令概览

2.1 语法与测试数据准备

realpath 的语法为 realpath [OPTION]... FILE...(摘自帮助 Usage 行),职责一句话(帮助原文):"Print the resolved absolute file name; all but the last component must exist"——把给定路径规范化为绝对路径:逐段跟随软链、消解 . 与 ..,约束是除最后一个成分外其余必须存在。配合 -e/-m 可以把存在性要求收紧或放开。

💡 技术拓展:"把路径变成规范绝对路径"有几种等价或相近的做法,横向对比——

工具原理/职责适用场景
realpath规范化绝对路径,-e/-m 控制存在性策略脚本里拿到唯一确定的规范路径
readlink -f以软链为主要目标的等价规范化与 realpath -e 结果一致(3.10 实测)
cd -P + pwd切进物理路径再取当前目录交互式 shell 场景
readlink(无 -f)只解析最后一段软链记录值只关心"这个链接直接指向哪"

本文主角是 realpath:coreutils 专用的路径规范化工具,--relative-to/--relative-base 还能直接输出相对路径(3.8/3.9 实测)。

准备一套演示数据,覆盖软链的四种典型形态:

mkdir -p /root/demo/realpath/real/sub /root/demo/realpath/deepdir/sub
cat > /root/demo/realpath/real/sub/file.txt <<'EOF'
demo
EOF
cat > /root/demo/realpath/deepdir/sub/deep.txt <<'EOF'
deep
EOF
ln -s /root/demo/realpath/real/sub/file.txt /root/demo/realpath/abs.lnk
ln -s real/sub/file.txt /root/demo/realpath/rel.lnk
ln -s /root/demo/realpath/nowhere.txt /root/demo/realpath/dangling.lnk
ln -s /root/demo/realpath/deepdir/sub /root/demo/realpath/t.lnk

验证数据就绪:

$ ls -l /root/demo/realpath
total 8
lrwxrwxrwx 1 root root   37 Oct 15 06:35 abs.lnk -> /root/demo/realpath/real/sub/file.txt
lrwxrwxrwx 1 root root   31 Oct 15 06:35 dangling.lnk -> /root/demo/realpath/nowhere.txt
drwxr-xr-x 3 root root 4096 Oct 15 06:35 deepdir
drwxr-xr-x 3 root root 4096 Oct 15 06:35 real
lrwxrwxrwx 1 root root   17 Oct 15 06:35 rel.lnk -> real/sub/file.txt
lrwxrwxrwx 1 root root   31 Oct 15 06:35 t.lnk -> /root/demo/realpath/deepdir/sub

四种软链分别是:绝对目标(abs.lnk)、相对目标(rel.lnk)、悬空(dangling.lnk,目标不存在)、指向深层目录(t.lnk),外加 .. 解析实验要用的目录层级。

2.2 --help 全量回显

realpath --help 输出全部参数清单(实测原样保留,可作为参数速查):

Usage: realpath [OPTION]... FILE...
Print the resolved absolute file name;
all but the last component must exist

  -e, --canonicalize-existing  all components of the path must exist
  -m, --canonicalize-missing   no path components need exist or be a directory
  -L, --logical                resolve '..' components before symlinks
  -P, --physical               resolve symlinks as encountered (default)
  -q, --quiet                  suppress most error messages
      --relative-to=DIR        print the resolved path relative to DIR
      --relative-base=DIR      print absolute paths unless paths below DIR
  -s, --strip, --no-symlinks   don't expand symlinks
  -z, --zero                   end each output line with NUL, not newline

      --help     display this help and exit
      --version  output version information and exit

GNU coreutils online help: <https://www.gnu.org/software/coreutils/>
Report any translation bugs to <https://translationproject.org/team/>
Full documentation <https://www.gnu.org/software/coreutils/realpath>
or available locally via: info '(coreutils) realpath invocation'

💡 说明:帮助原文里两个 .. 解析方向的参数值得记牢——-L 是"先消解 .. 再处理软链"(逻辑模式),-P 是"遇到软链就解引用"(物理模式,默认)。3.5 用 t.lnk 给出了两者的分野实测。

2.3 版本确认

$ realpath --version | head -1
realpath (GNU coreutils) 8.32

三、参数逐项实测

本章逐个参数给出「命令 + 实测回显 + 说明」,所有回显与服务器日志逐字一致;演示文件全部位于 /root/demo/realpath/。

3.1 默认行为:规范化为绝对路径(末段可不存在的宽容)

不带参数的 realpath 输出规范化后的绝对路径:软链被解析、.. 被消解:

$ realpath /root/demo/realpath/rel.lnk
/root/demo/realpath/real/sub/file.txt
$ realpath /root/demo/realpath/../realpath/real/sub/file.txt
/root/demo/realpath/real/sub/file.txt

相对软链 rel.lnk 被解析到真实文件;纯文本上的 ../realpath 绕行也被消解。对不存在的末段,默认模式依然返回计划中的规范化路径(退出码 0):

$ realpath /root/demo/realpath/nosuch.txt; echo exit=$?
/root/demo/realpath/nosuch.txt
exit=0

但中间成分缺失就失败——软链解析依赖路径逐段存在:

$ realpath /root/demo/realpath/ghostdir/file.txt; echo exit=$?
realpath: /root/demo/realpath/ghostdir/file.txt: No such file or directory
exit=1

约束总结:除末段外全部必须存在(帮助原文 "all but the last component must exist")。

3.2 -e:所有成分必须存在

-e(--canonicalize-existing)比默认更严:包括末段在内所有成分都必须存在,否则失败:

$ realpath -e /root/demo/realpath/rel.lnk; echo exit=$?
/root/demo/realpath/real/sub/file.txt
exit=0

全段存在则成功。两个典型失败案例——末段不存在、以及悬空软链(解析出的目标不存在):

$ realpath -e /root/demo/realpath/dangling.lnk; echo exit=$?
realpath: /root/demo/realpath/dangling.lnk: No such file or directory
exit=1
$ realpath -e /root/demo/realpath/nosuch.txt; echo exit=$?
realpath: /root/demo/realpath/nosuch.txt: No such file or directory
exit=1

对比 3.1:同是 nosuch.txt,默认模式成功返回路径,-e 直接失败。需要"结果路径一定真实可访问"的保证时用 -e,比如写入文件前的安全校验。

3.3 -m:任何成分都可以不存在

-m(--canonicalize-missing)最宽松:只做软链解析与文本规范化,完全不检查存在性:

$ realpath -m /root/demo/realpath/ghostdir/file.txt; echo exit=$?
/root/demo/realpath/ghostdir/file.txt
exit=0
$ realpath -m /root/demo/realpath/nosuch.txt; echo exit=$?
/root/demo/realpath/nosuch.txt
exit=0

三档存在性约束的实测汇总(结果均来自上面各节的回显):

参数存在性约束nosuch.txt(末段缺失)ghostdir/file.txt(中间段缺失)
默认除末段外必须存在成功(exit=0,输出规范化路径)失败(exit=1)
-e全部成分必须存在失败(exit=1)失败(exit=1)
-m不检查存在性成功(exit=0)成功(exit=0)

选型一句话:常规取真实路径用默认(对"目标尚未创建"宽容);结果必须可访问用 -e;纯字符串规范化(如拼装计划中的路径)用 -m。

3.4 -s:不展开软链(只绝对化,不解链)

-s(--strip / --no-symlinks)跳过软链解析,只把路径变成绝对形式。同一个软链,加不加 -s 结果完全不同:

$ realpath -s /root/demo/realpath/rel.lnk
/root/demo/realpath/rel.lnk
$ realpath /root/demo/realpath/rel.lnk
/root/demo/realpath/real/sub/file.txt
$ realpath -s /root/demo/realpath/abs.lnk
/root/demo/realpath/abs.lnk

-s 返回的是"这个链接文件自己"的绝对路径;默认模式返回的是"链接指向的目标"的绝对路径。想拿软链自身的绝对路径(比如在脚本里比对"当前是不是这个链接")时用 -s。

3.5 -P 与 -L:.. 的物理解析与逻辑解析

-P(--physical,默认)遇到软链就解引用;-L(--logical)先把 .. 在文本上与前面的成分相消、再处理软链。演示数据里 t.lnk 指向深层目录 deepdir/sub,考察 t.lnk/..:

$ realpath /root/demo/realpath/t.lnk/..
/root/demo/realpath/deepdir
$ realpath -P /root/demo/realpath/t.lnk/..
/root/demo/realpath/deepdir
$ realpath -L /root/demo/realpath/t.lnk/..
/root/demo/realpath

默认与 -P 一致:t.lnk 先被解析成 /root/demo/realpath/deepdir/sub,其上的 .. 得到 deepdir(物理事实)。-L 则把 t.lnk/.. 在文本上相消成"t.lnk 的父目录",得到 /root/demo/realpath(逻辑视角)。处理"用户从目录软链进入、想返回上一级"这类语义时,-L 的答案通常更符合直觉。

3.6 -q:抑制错误消息(退出码保留)

默认失败时向 stderr 输出原因(见 3.1);-q(--quiet)抑制错误消息,但退出码不变:

$ realpath -q /root/demo/realpath/ghostdir/file.txt; echo exit=$?
exit=1
$ realpath -q /root/demo/realpath/rel.lnk; echo exit=$?
/root/demo/realpath/real/sub/file.txt
exit=0

失败时零输出、退出码 1;成功时输出照常。适合"只关心成败、错误自行处理"的脚本判断,典型写法是 realpath -q 路径 >/dev/null 配合 if 按退出码分支。

3.7 -z:NUL 结尾输出

-z(--zero)用 NUL 字节替代换行作为分隔符,多路径结果逐个以 \0 相接。用 xxd 验证字节级内容:

$ realpath -z /root/demo/realpath/rel.lnk /root/demo/realpath/abs.lnk | xxd
00000000: 2f72 6f6f 742f 6465 6d6f 2f72 6561 6c70  /root/demo/realp
00000010: 6174 682f 7265 616c 2f73 7562 2f66 696c  ath/real/sub/fil
00000020: 652e 7478 7400 2f72 6f6f 742f 6465 6d6f  e.txt./root/demo
00000030: 2f72 6561 6c70 6174 682f 7265 616c 2f73  /realpath/real/s
00000040: 7562 2f66 696c 652e 7478 7400            ub/file.txt.

两条解析结果各以一个 NUL 字节(xxd 中的 00)结尾后相接。文件名可能含换行符时,消费端用 xargs -0、read -d '' 读取更安全。

3.8 --relative-to:输出相对路径

--relative-to=DIR 把解析结果表示为相对 DIR 的路径:

$ realpath --relative-to=/root/demo /root/demo/realpath/real/sub/file.txt
realpath/real/sub/file.txt
$ realpath --relative-to=/root/demo/realpath/real /root/demo/realpath/real/sub/file.txt
sub/file.txt

同一个文件,基准不同得到不同的相对串,且基准可以是任意层级。生成报告、拼接 URL、写构建脚本里的相对引用时非常顺手。

💡 说明:--relative-to 等价于"先分别规范化两个路径,再裁掉公共前缀"——所以基准传相对路径、软链路径都能得到正确结果(内部先解析)。基准不是前缀时会输出 ../ 回溯,这也是它与单纯字符串替换的本质区别。

3.9 --relative-base:在基准之下才转相对

--relative-base=DIR 是带条件的相对输出:路径位于 DIR 之下时输出相对路径,否则保持绝对:

$ realpath --relative-base=/root/demo /root/demo/realpath/real/sub/file.txt /etc/hostname
realpath/real/sub/file.txt
/etc/hostname

第一个参数在 /root/demo 之下,输出相对路径;第二个参数 /etc/hostname 在基准之外,保持绝对路径原样输出。批量处理"目录内用相对、目录外用绝对"的路径清单时一个参数搞定。

规范化这个场景上,两者同源:对同一路径,readlink -f 与默认 realpath 输出完全一致:

$ readlink -f /root/demo/realpath/rel.lnk
/root/demo/realpath/real/sub/file.txt
$ realpath /root/demo/realpath/rel.lnk
/root/demo/realpath/real/sub/file.txt

差异在能力面:--relative-to 是 realpath 独有的,readlink 没有对应参数:

$ readlink -f --relative-to=/tmp /root/demo/realpath/rel.lnk; echo exit=$?
readlink: unrecognized option '--relative-to=/tmp'
Try 'readlink --help' for more information.
exit=1

结论:只要规范化,两者任选;需要相对路径输出(--relative-to/--relative-base)、-s 不解链等进阶能力时,用 realpath。多路径也逐行输出:

$ realpath /root/demo/realpath/rel.lnk /root/demo/realpath/abs.lnk
/root/demo/realpath/real/sub/file.txt
/root/demo/realpath/real/sub/file.txt

相对软链与绝对软链殊途同归,都解析到同一个真实文件。

四、实战示例

4.1 取软链的真实绝对路径

$ realpath /root/demo/realpath/rel.lnk
/root/demo/realpath/real/sub/file.txt

运维中最常见的用法:确认多级软链(如 /usr/bin/python3)最终指向哪个真实文件,脚本里用它把"可能被软链包装的路径"还原成绝对路径。

4.2 生成基准目录下的相对路径

$ realpath --relative-to=/root/demo /root/demo/realpath/real/sub/file.txt
realpath/real/sub/file.txt

把绝对路径转成相对引用(报告、构建脚本、URL 拼接);基准之外保持绝对的条件形态见 3.9 的 --relative-base 实测。

4.3 写入前校验路径真实存在

$ realpath -e /root/demo/realpath/rel.lnk; echo exit=$?
/root/demo/realpath/real/sub/file.txt
exit=0

-e 退出码 0 表示全段存在、结果可访问;对悬空软链它会失败(见 3.2)。把它作为写入、删除等危险操作前的守门检查最合适。

五、注意事项与常见问题

Q1:realpath 对不存在的路径为什么也能成功? 默认约束是"除末段外必须存在":末段缺失时输出计划中的规范化路径、退出码 0;中间目录缺失才失败(见 3.1 的正反实测)。

Q2:默认、-e、-m 到底选哪个? 看存在性要求:宽容(目标可未建)用默认,严格(必须真实可访问)用 -e,纯字符串规范化用 -m(见 3.3 的对照表)。

Q3:悬空软链为什么过不了 -e? -e 要求解析结果的每个成分都存在,悬空软链解析出的目标不存在,自然失败(见 3.2);默认模式只解析不校验存在性。

Q4:-s 拿到的路径和默认有什么不同? -s 返回软链文件自身的绝对路径(不解链),默认返回链接指向目标的绝对路径(见 3.4 同一链接的两种结果)。

Q5:-P 和 -L 的结果为什么不一样? 对"软链/.." 这类路径,-P(默认)先解引用软链再算 ..(物理位置),-L 先在文本上消解 ..(逻辑位置),见 3.5 的 t.lnk 实测。

Q6:realpath 和 readlink -f 怎么选? 纯规范化两者输出一致(见 3.10);需要相对路径输出、-s 不解链等能力时只有 realpath 能做(readlink 对 --relative-to 直接报 unrecognized option)。

Q7:-q 把错误都吞了,怎么排障? -q 只抑制消息、保留退出码,判断成败够用;要看失败原因就去掉 -q,错误文本在 stderr(对比 3.1 与 3.6 的输出)。

Q8:一次处理多个路径安全吗? 支持多参数、逐行输出(见 3.10);路径来源不可信(可能含换行)时加 -z 用 NUL 分隔,消费端配 xargs -0(见 3.7)。

六、参考链接