如何查找文件所在的挂载点?

时间:2010-12-15 18:40:37

标签: python linux unix filesystems

例如,我有一个包含以下路径的文件:

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

我已经走完了整条道路,想要得到:

/media/my_mountpoint

我该怎么做?最好是在Python中,不使用外部库/工具。 (两者都不是必需的。)

8 个答案:

答案 0 :(得分:17)

您可以调用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

答案 1 :(得分:5)

因为python不是必需的:

df "$filename" | awk 'NR==1 {next} {print $6; exit}'

NR==1 {next}是跳过df输出的标题行。 $6是挂载点。 exit是为了确保我们只输出一行。

答案 2 :(得分:4)

由于现在我们无法真正可靠地解析由mountUUID挂载文件系统的系统中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
  • 其inode编号(%i)为461246。

仅供记录,这是来自GNU coreutilsstat版本,这意味着其他一些版本(例如BSD)默认情况下可能没有它(但你可以随时使用您首选的包管理器安装它。)

答案 3 :(得分:2)

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

我正在使用的计算机有Linux和OS X分区。当文件管理器应用程序(在根Linux分区上运行)尝试索引OS X分区上的文件时,它会很快遇到从“/ media / mac-hd /用户指南和信息”到“/”的绝对符号链接图书馆/文献/用户指南和信息。本地化“和扼流圈。问题是文件管理器在它自己的文件系统上寻找该链接的绝对目标,而不是在/ media / mac-hd上安装的OS X分区。因此,我需要一种方法来识别文件位于不同的挂载点上,并将该挂载点预先添加到链接的绝对目标。

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

我注意到不安全的评论下面的答案是关于如何使用符号链接,并且还注意到他对/ 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

答案 4 :(得分:0)

我的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周围的 “''” ,否则无效。

// edit:python solution:

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

答案 5 :(得分:0)

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

答案 6 :(得分:-3)

/bin/mountpoint [-q] [-d] /path/to/directory

答案 7 :(得分:-3)

import os

def find_mount_point(path):
    while not os.path.ismount(path):
        path=os.path.dirname(path)
    return path