如何find文件所在的安装点?

例如,我有一个具有以下path的文件:

/media/my_mountpoint/path/to/file.txt 

我已经走完了整条路,希望得到:

 /media/my_mountpoint 

我怎样才能做到这一点? 最好在Python中,不要使用外部库/工具。 (两者都不是要求)

Solutions Collecting From Web of "如何find文件所在的安装点?"

您可以调用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是确保我们只输出一行。

由于现在我们不能真正可靠地解析UUIDLABEL挂载文件系统的系统的mount内容,因为输出可能包含如下内容:

 (...) /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 

在上面的输出中,我们可以看到:

  • Talks中硬链接的数量( %h )是6
  • 挂载点( %m )是/media/lattes
  • 其inode号( %i )是461246。

只是为了记录,这是从GNU coreutils的stat版本,这意味着其他一些版本(如BSD)可能没有默认情况下(但你可以随时安装你喜欢的包管理器)。

我正在使用Python中的GTK + 3文件管理器,并且在循环文件时遇到同样的需求。

我正在使用的计算机有Linux和OS X分区。 当文件管理器应用程序(运行在根分区上的Linux)尝试索引OS X分区上的文件时,它会很快遇到从“/ media / mac-hd /用户指南和信息”到“/图书馆/文件/用户指南和Information.localized“和呛。 问题是,文件管理器正在寻找它自己的文件系统上的链接的绝对目标,而不是在/ media / mac-hd上挂载OS X分区。 所以,我需要一种方法来确定一个文件是在不同的挂载点上,并将该挂载点预先挂载到链接的绝对目标上。

我从Fred Foo的回答中编辑的解决方案开始。 这似乎有助于提供解决方案,我正试图解决的具体错误。 当我打电话给find_mount_point('/media/mac-hd/User Guides And Information') ,它会返回/media/mac-hd 。 太好了,我想。

我注意到在关于使用符号链接的答案下面的不安全的评论,并且还注意到他对/ var / run是正确的:

要使你的代码符合symlinks,例如/ var / run – > ../run,用os.path.realpath()或者find_mount_point()替换os.path.abspath() find_mount_point()将返回“/”。

当我尝试用os.path.abspath()替换os.path.abspath()时,我会得到/var/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 

我的蟒蛇是生锈的,但是你可以使用这样的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 

@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)) } 
 /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