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

k97glaaz  于 2023-11-17  发布在  Linux
关注(0)|答案(9)|浏览(138)

例如,我有一个文件,路径如下:

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

字符串
我已经得到了整个路径,我想得到:

/media/my_mountpoint


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

wvyml7n5

wvyml7n51#

您可以调用mount命令并解析其输出,以找到路径中最长的公共前缀,或者使用stat系统调用来获取文件所在的设备,然后沿着树向上查找,直到到达另一个设备。
在Python中,stat可以按如下方式使用(未经测试,可能需要扩展以处理符号链接和union mounts之类的外来内容):

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

yacmzcpb

yacmzcpb2#

由于Python不是必需的:

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

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

mnemlml8

mnemlml83#

由于现在我们无法在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 coreutilsstat版本一起使用的,这意味着其他一些版本(例如BSD)可能默认没有它(但您可以始终使用首选的包管理器安装它)。

l2osamch

l2osamch4#

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

字符串

ds97pgxw

ds97pgxw5#

我在Python中使用GTK+ 3文件管理器,在循环文件时遇到了同样的需求。
我使用的计算机有Linux和OS X分区。(运行在根Linux分区上)将尝试索引OSX分区上的文件,它会很快遇到一个从“/media/mac-hd/UserGuides And Information”到“/Library/Documentation/UserGuides and Information.localized”的绝对符号链接问题是文件管理器在自己的文件系统上寻找该链接的绝对目标,而不是在/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.realpath()替换os.path.abspath(),否则find_mount_point()将返回“/"。
当我尝试用os.path.realpath()替换os.path.abspath()时,我会得到/var/run的正确的/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

字符串

dy1byipe

dy1byipe6#

我的python是rusty,但你可以使用这样的东西与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解决方案:

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

aurhwmvo

aurhwmvo7#

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

字符串

j2cgzkjk

j2cgzkjk8#

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

字符串

yqhsw0fo

yqhsw0fo9#

import os

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

字符串

相关问题