例如,我有一个具有以下路径的文件:
/media/my_mountpoint/path/to/file.txt
我已经有了完整的路径并且想要得到:
/media/my_mountpoint
我该怎么做?最好使用 Python 并且不使用外部库/工具。 (两者都不是必需的。)
您可以调用
mount
命令并解析其输出以查找与您的路径最长的公共前缀,或者使用 stat
系统调用来获取文件所在的设备并沿着树向上查找,直到到达不同的设备。
在Python中,
stat
可以按如下方式使用(未经测试,可能需要扩展以处理符号链接和联合挂载等奇异的东西):
def find_mount_point(path):
path = os.path.abspath(path)
orig_dev = os.stat(path).st_dev
while path != '/':
dir = os.path.dirname(path)
if os.stat(dir).st_dev != orig_dev:
# we crossed the device border
break
path = dir
return path
编辑:直到现在我才知道
os.path.ismount
。这大大简化了事情。
def find_mount_point(path):
path = os.path.abspath(path)
while not os.path.ismount(path):
path = os.path.dirname(path)
return path
因为 python 不是必需的:
df "$filename" | awk 'NR==1 {next} {print $6; exit}'
NR==1 {next}
是跳过df输出的标题行。 $6
是挂载点。 exit
是为了确保我们只输出一行。
现在我们无法真正可靠地在通过
mount
或 UUID
挂载文件系统的系统中解析 LABEL
的内容,因为输出可能包含类似以下内容:
(...)
/dev/disk/by-uuid/00000000-0000-0000-0000-000000000000 on / type ext4 (rw,relatime,errors=remount-ro,data=ordered)
(...)
我们需要一个更强大的解决方案(例如,考虑像上面这样的路径的“切割”部分可能会导致什么,以及我们是否想要类似的东西)。
其中一个解决方案(顺便说一句,尝试不要重新发明轮子)是简单地使用
stat
命令来发现文件所在的挂载点,如下所示:
$ stat --printf "%h:%m:%i\n" Talks
6:/media/lattes:461246
在上面的输出中,我们可以看到:
%h
中的硬链接 (Talks
) 数量为 6%m
) 是 /media/lattes
%i
)是461246。仅供记录,这是来自 GNU
coreutils的
stat
版本,这意味着某些其他版本(例如 BSD)默认情况下可能没有它(但您始终可以使用您喜欢的软件包安装它)经理)。
@larsmans 非常好的答案,这非常有帮助!我已经在 Golang 中我需要的地方实现了这个。
对于对代码感兴趣的人(已针对 OS X 和 Linux 进行过测试):
package main
import (
"os"
"fmt"
"syscall"
"path/filepath"
)
func Mountpoint(path string) string {
pi, err := os.Stat(path)
if err != nil {
return ""
}
odev := pi.Sys().(*syscall.Stat_t).Dev
for path != "/" {
_path := filepath.Dir(path)
in, err := os.Stat(_path)
if err != nil {
return ""
}
if odev != in.Sys().(*syscall.Stat_t).Dev {
break
}
path = _path
}
return path
}
func main() {
path, _ := filepath.Abs("./")
dir := filepath.Dir(path)
fmt.Println("Path", path)
fmt.Println("Dir", dir)
fmt.Println("Mountpoint", Mountpoint(path))
}
我正在用 Python 开发 GTK+ 3 文件管理器,在循环文件时遇到了同样的需求。
我使用的计算机有 Linux 和 OS X 分区。当文件管理器应用程序(在 Linux 根分区上运行)尝试对 OS X 分区上的文件进行索引时,它很快就会遇到从“/media/mac-hd/User Guides And Information”到“/图书馆/文档/用户指南和信息。本地化”并窒息。问题是文件管理器正在其自己的文件系统上寻找该链接的绝对目标,而该链接并不存在,而不是安装在 /media/mac-hd 的 OS X 分区。因此,我需要一种方法来识别文件位于不同的安装点上,并将该安装点添加到链接的绝对目标之前。
我从Fred Foo的答案中编辑的解决方案开始。它似乎有助于为我试图解决的特定错误提供解决方案。当我调用
find_mount_point('/media/mac-hd/User Guides And Information')
时,它会返回/media/mac-hd
。太棒了,我想。
我注意到 insecure 在关于使其与符号链接一起工作的答案下面的评论,并且还注意到他关于 /var/run 的说法是正确的:
使您的代码可以使用符号链接,例如/var/run -> ../run,将
替换为os.path.abspath()
或os.path.realpath()
将返回“/”。find_mount_point()
当我尝试用
os.path.abspath()
替换 os.path.realpath()
时,我会得到 /run
的正确返回值 /var/run
。但是我也注意到,在调用 find_mount_point('/media/mac-hd/User Guides And Information')
时我将不再获得我想要的值,因为它现在返回 /
。
以下是我最终使用的解决方案。也许可以简化:
def find_mount_point(path):
if not os.path.islink(path):
path = os.path.abspath(path)
elif os.path.islink(path) and os.path.lexists(os.readlink(path)):
path = os.path.realpath(path)
while not os.path.ismount(path):
path = os.path.dirname(path)
if os.path.islink(path) and os.path.lexists(os.readlink(path)):
path = os.path.realpath(path)
return path
我的 python 生锈了,但是你可以在 perl 中使用类似的东西:
export PATH_TO_LOOK_FOR="/media/path";
perl -ne '@p = split /\s+/; print "$p[1]\n" if "'$PATH_TO_LOOK_FOR'" =~ m@^$p[1]/@' < /proc/mounts
注意 $PATH_TO_LOOK_FOR 周围的 " ' ' " 否则它将无法工作。
//编辑:python解决方案:
def find_mountpoint(path):
for l in open("/proc/mounts", "r"):
mp = l.split(" ")[1]
if(mp != "/" and path.find(mp)==0): return mp
return None
os.path.realpath
删除符号链接,因此更简洁:
def find_mountpoint(path):
"""Find the non-symlinked mountpoint of a path."""
path = os.path.realpath(path)
while not os.path.ismount(path):
path = os.path.dirname(path)
return path
/bin/mountpoint [-q] [-d] /path/to/directory
import os
def find_mount_point(path):
while not os.path.ismount(path):
path=os.path.dirname(path)
return path