使用pathlib获取符号链接的目标

11
有没有一种使用 pathlib 获取符号链接目标的方法?我知道可以使用 os.readlink() 来实现此目的。
我想创建一个由链接和它们的目标文件组成的字典。
links = [link for link in root.rglob('*') if link.is_symlink()]
files = [Path(os.readlink(str(pointed_file))) for pointed_file in links]

编辑... 我想过滤掉所有不是绝对路径的路径

    link_table = {link : pointed_file for link, pointed_file in zip(links, files) if pointed_file.is_absolute()}
2个回答

20

更新:Python 3.9 引入了 Path.readlink() 方法,下面的解释仅适用于早期版本。

目前无法通过 pathlib 获得与 os.readlink() 相同的结果。对于损坏的链接,Path.resolve() 无法工作并且会引发 FileNotFoundError(Python < 3.5)或返回可能奇怪的路径(Python 3.6)。仍然可以使用 Path.resolve(True) 获取旧行为,但这意味着存在版本不兼容性(顺便说一下,在软件包文档和 Py3.6 发布文档的迁移部分中没有提到)。

关于有关绝对路径的更新问题,os.readlink() 是检查符号链接是绝对路径还是相对路径的唯一方法。Path.relative_to() 如其名称所示,将现有路径转换为相对路径,而不检查符号链接目标路径是否以'/'开头。同样适用于 Path.is_absolute()。最后,对于现有目标,Path.resolve() 将目标路径转换为绝对路径,并破坏所需的信息。

我所说的“奇怪路径”是指,在/home/test中有一个符号链接.myapp指向.config/myapp/config。如果.config/myapp不存在并且代码编写在Py≤3.5上,Path.resolve()将引发异常,并且应用程序可以通知用户缺少的文件。现在如果从Py3.6调用而没有进行代码更改,则它会解析为~/.config/myapp,不会抛出异常,因此在.resolve()周围检查通过,但是接下来可能会抛出另一个异常,当应用程序尝试打开文件进行读取时,用户可能会收到消息,即未找到~/config/myapp文件,尽管实际上这里缺少的不是那个文件。甚至可能更糟糕-当应用程序执行Path('/home/test/.myapp').resolve().open('w')(不一定是一步操作,但假设作为某些净化过程的一部分),然后会创建错误的文件。当然,下一次调用应用程序时,路径将深入一级,变成/home/test/.config/myapp/config(因为Path.resolve()不检查myapp是目录还是文件),读取和写入都将失败并引发NotADirectoryError异常(带有一个略微误导性的描述:“不是目录:/ home / test / .config / myapp / config”)。

2
似乎有必要说明自从3.9版本以来如何实现。
这比预期的要困难一些。您需要检查`is_symlink()`,`readlink`然后再检查`readlink`的结果是否是绝对路径`is_absolute`。
`readlink`的文档说:
返回符号链接指向的路径(由os.readlink()返回):
即 `Path("./file1").readlink()` => `PosixPath('../files/file1')` 对于我测试文件中的相对符号链接。
代码本身:
from pathlib import Path

cwd = Path(".")

#is it a link?
links = [pa for pa in (cwd / "links").glob("*") if pa.is_symlink()]

#you have to read the link and check if readlink's result is absolute
di_abs = { str(link) : str(v)  for link in links if (v:=link.readlink()).is_absolute()}

for k,v in di_abs.items():
    print(f" {k:20.20} => {v}"

输出结果,假设我理解了要求:
 links/file3          => /Users/me/kds2/wk/explore/test_430_readlink.py/files/file3
 links/file2          => /Users/me/kds2/wk/explore/test_430_readlink.py/files/file2

用于测试的文件树形结构

├── files
│   ├── file1
│   ├── file2
│   └── file3
├── links          `readlink()` result
│   ├── file1 -> ../files/file1
│   ├── file2 -> /Users/me/kds2/wk/explore/test_430_readlink.py/files/file2
│   ├── file3 -> /Users/me/kds2/wk/explore/test_430_readlink.py/files/file3
│   └── realfile4

设置测试的Shell脚本

(需要安装realpath,适用于macOS)

rm -rf links files

mkdir files
cd files
echo file1contents > file1
echo file2contents > file2
echo file3contents > file3

cd ..
mkdir links
cd links

ln -s ../files/file1
ln -s $(realpath ../files/file2)
ln -s $(realpath ../files/file3)

echo realfile4contents > realfile4

cd ..



网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接