Как найти точку монтирования файла? - PullRequest
15 голосов
/ 15 декабря 2010

Например, у меня есть файл со следующим путем:

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

Я прошел весь путь и хочу получить:

/media/my_mountpoint

Как я могу это сделать? Желательно в Python и без использования внешних библиотек / инструментов. (Оба не являются обязательными.)

Ответы [ 8 ]

17 голосов
/ 15 декабря 2010

Вы можете либо вызвать команду mount и проанализировать ее вывод, чтобы найти самый длинный общий префикс с вашим путем, либо использовать системный вызов stat, чтобы получить устройство, на котором находится файл, и переходить вверх по дереву, пока не получитена другое устройство.

В Python stat может использоваться следующим образом (не проверено и может быть расширено для обработки символических ссылок и экзотических вещей, таких как union mount):

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
5 голосов
/ 16 декабря 2010

Поскольку python не является обязательным требованием:

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

NR==1 {next} - пропустить строку заголовка, которую выводит df. $6 - точка монтирования. exit - убедитесь, что мы выводим только одну строку.

4 голосов
/ 07 марта 2013

Поскольку в настоящее время мы не можем надежно проанализировать содержимое 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.

Просто для записи, это с версией stat из GNU coreutils , что означает, что некоторые другие версии (например, BSD) могут не иметь ее по умолчанию (но вы всегда можете установите его с вашим предпочтительным менеджером пакетов).

2 голосов
/ 12 июля 2016

Я работал над файловым менеджером GTK + 3 в Python и столкнулся с той же необходимостью при циклическом просмотре файлов.

Компьютер, на котором я работал, имеет разделы Linux и OS X.Когда приложение менеджера файлов (работающее в корневом разделе Linux) попытается проиндексировать файлы в разделе OS X, оно быстро встретит абсолютную символическую ссылку из "/ media / mac-hd / Руководства пользователя и информация" в "/Библиотека / Документация / Руководства пользователя и информация. Локализовано "и подавиться.Проблема заключалась в том, что файловый менеджер искал абсолютную цель этой ссылки в собственной файловой системе, где она не существует, вместо раздела OS X, смонтированного в / media / mac-hd.Итак, мне нужен был способ определить, что файл находится в другой точке монтирования, и добавить эту точку монтирования к абсолютной цели ссылки.

Я начал с отредактированного решения в 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() return "/".

Когда я попытался заменить 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
0 голосов
/ 24 декабря 2015

@ larsmans Очень хороший ответ, это было очень полезно! Я реализовал это на Голанге, где мне это было нужно.

Для людей, которые заинтересованы в коде (это было проверено для 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))
}
0 голосов
/ 03 июля 2014
import os

def find_mount_point(path):
    while not os.path.ismount(path):
        path=os.path.dirname(path)
    return path
0 голосов
/ 15 декабря 2010

Мой питон ржавый, однако вы можете использовать что-то подобное с 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
0 голосов
/ 15 декабря 2010
/bin/mountpoint [-q] [-d] /path/to/directory
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...