realpath 命令详解与参数实测(Ubuntu 22.04)
GNU realpath 参数实测:默认规范化、-e/-m/-s/-P/-L/-q/-z 与 --relative-to 相对路径,及与 readlink -f 的等价差异,Ubuntu 22.04 实测。
realpath 命令详解与参数实测(Ubuntu 22.04)
目标:全面掌握 GNU realpath 的每一个参数——默认规范化、
-e/-m存在性约束、-s不展开软链、-P/-L物理与逻辑解析、-q静默、-zNUL 结尾、--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 在基准之外,保持绝对路径原样输出。批量处理"目录内用相对、目录外用绝对"的路径清单时一个参数搞定。
3.10 与 readlink -f 的等价与差异
规范化这个场景上,两者同源:对同一路径,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)。
六、参考链接
- GNU coreutils 官方手册(realpath 章节):https://www.gnu.org/software/coreutils/manual/html_node/realpath-invocation.html
- 在线文档:https://www.gnu.org/software/coreutils/realpath
- 本机帮助:
realpath --help、man realpath(Ubuntu 22.04 内置) - 关联手册页:
man readlink(软链记录值读取与-f规范化)、man symlink(软链解析机制)