Проверьте, размещены ли 2 каталога в одном разделе в Linux


9

Как я могу проверить, /my/dirнаходится ли на том же разделе, что и /?

Это для интеграции внутри скрипта. Крепления должны быть обработаны правильно. POSIX-совместимые решения приветствуются.


«Крепления для крепления должны быть обработаны правильно». Но что вы считаете правильным? Ваш вопрос может быть истолкован в любом случае.
Жиль "ТАК - перестань быть злым"

@Gilles В оригинальном названии я написал "размещенный" вместо "установленный", кто-то отредактировал добавив путаницу ИМХО. Тем не менее, мое тело вопроса ясно: «в том же разделе», то есть в том же физическом разделе, независимо от того, какой путь или точка монтирования использовались для доступа к двум файлам / каталогам.
Тотор

Ответы:


6

Вы можете проверить это с помощью stat:

$ stat -c '%d %m' /proc/sys/
3 /proc

Показывает номер устройства и где был установлен ваш каталог.


1
Хорошо, но команда statоболочки не POSIX ...
Totor

Нет? Откуда вы знаете?


О, мой плохой. Но в следующий раз покажи эту ссылку заранее.

5

Следующая команда дает уникальное имя для точки монтирования, содержащей файл $file:

df -P -- "$file" | awk 'NR==2 {print $1}'

Это работает в любой системе POSIX . -PВариант предусматривает предсказуемый формат; первое поле второй строки - это «имя файловой системы». Таким образом, для проверки два файла находятся в одной точке монтирования:

if [ "$(df -P -- "$file1" | awk 'NR==2 {print $1}')" = \
     "$(df -P -- "$file2" | awk 'NR==2 {print $1}')" ]; then
  echo "$file1 and $file2 are on the same filesystem" ; fi

Или, чтобы сохранить пару вызовов процесса:

if df -P -- "$file1" "$file2" |
   awk 'NR!=1 {dev[NR] = $1} END {exit(dev[2] != dev[3])}'; then
  echo "$file1 and $file2 are on the same filesystem" ; fi

Некоторые операционные системы могут иметь пробелы в именах томов. В этом случае нет абсолютно надежного способа анализа dfвыходных данных.

Под капотом вы можете идентифицировать файловую систему, содержащую файл, по st_devполю, возвращаемому stat. Нет переносимого способа сделать это из сценария оболочки. В некоторых системах есть statутилита, но ее синтаксис различен:

  • На не встроенных Linux, Cygwin или других системах с GNU coreutils, statсообщает st_devполе при вызове как stat -c %D -- "$file".
  • Некоторые установки BusyBox включают в себя, statкоторый совместим с GNU coreutils. Другие имеют statбез %cопции; Вы можете использовать, stat -t -- "$file" | awk '{print $8}'но это работает только в том случае, если имя файла не содержит пробелов, или stat -t -- "$file" | awk 'END {print $(NF-8)}'которое справляется с произвольными именами файлов, но не с будущими добавлениями полей к statвыводу.
  • Системы BSD имеют другую statутилиту, которая требует stat -f %d -- "$file".
  • Солярис, AIX и другие не имеют никакой statполезности.

Если Perl доступен, вы можете использовать

perl -e 'print ((stat($ARGV[0]))[0])' -- "$file"

и сделать сравнение:

perl -e 'exit((stat($ARGV[0]))[0] != (stat($ARGV[1]))[0])' -- "$file1" "$file2"

Обратите внимание, что в некоторых угловых случаях желаемый результат неясен. Например, с помощью связывания креплений для Linux, после того, как mount --bind /foo /bar, /fooи /barсчитаются одной файловой системой. Всегда возможно, что эти два файла фактически расположены на одном устройстве, но вы никогда не узнаете: например, если файлы находятся на двух разных сетевых подключениях, клиент не сможет узнать, экспортирует ли сервер разные файловые системы.

Если файлы являются каталогами, и вы можете записать в них, другой метод - создать временный файл и попытаться создать жесткую ссылку. Этот отчет сообщает об отрицательном результате при использовании Linux bind mounts.

tmp1=$(TMPDIR=$dir1 mktemp)
tmp2=$(TMPDIR=$dir2 mktemp)
if ln -f -- "$tmp1" "$tmp2"; then
  echo "$dir1 and $dir2 are on the same filesystem, which supports hard links"
fi
rm -f "$tmp1" "$tmp2"

Проблема: dfне всегда дает имя устройства, но иногда символическая ссылка на него, например, /dev/disk/by-uuid/ca09b761-ae1b-450f-8a46-583327b48fb4делает dfне надежным. Пока единственным надежным вариантом является использование statрешения на основе.
Тотор

@Totor Это не имеет значения: какое бы имя не dfсообщалось для устройства, оно согласовано между двумя вызовами, поэтому для сравнения все в порядке.
Жиль "ТАК - перестань быть злым"

Нет, это не работает, я проверял это. На Debian Wheezy здесь один dfотчет /dev/sda6и /dev/disk/by-uuid/ca09b..., оба ссылаются на одно и то же устройство, но разные точки монтирования. При сравнении файлов из каждой точки монтирования проверка сравнения строк явно не проходит.
Тотор

@Totor Обычно нельзя установить одно и то же блочное устройство дважды. Как я указываю в своем ответе, существуют угловые случаи, такие как крепления, которые могут или не могут быть указаны как отдельные.
Жиль "ТАК - перестань быть злым"

Тем не менее, он отлично работает на Debian Squeeze и Wheezy: mount /dev/sda6 /mnt1за ним следует mount /dev/sda6 /mnt2работа, как шарм. cat /proc/mountsхорошо с этим. Тем не менее, только с тех пор, как Wheezy /dev/disk/by-uuid/ca09b...отображается dfкак устройство для корневой файловой системы. Дальнейшие попытки установить его с помощью этого SimLink или UUID=ca09b...смонтировать синтаксис не до конца , показывая что - нибудь еще , чем /dev/sda6в df(я не знаю , как воспроизвести то , что это было сделано во время процесса загрузки, но это не забота здесь).
Тотор

4
test $(df -P $path1 $path2 | awk '{if (NR!=1) {print $6}}' | uniq | wc -l) -eq 1

Работает с любым количеством путей.


Синтаксический вывод dfявляется не всегда хорошей идеей .
Джозеф Р.

1
@Totor Я проверяю точку монтирования ( $6), а не имя устройства ( $1), так что это не должно быть проблемой.
n.st

1
@JosephR Это лучшее, что есть в POSIX. n.st: почему бы не проверить первое поле? Неважно, какой путь использовался для доступа к устройству, если это та же точка монтирования, то выходные данные будут согласованы.
Жиль "ТАК - перестань быть злым"

Это не работает с креплениями.
Тотор

0

Лучшее надежное решение, доступное в POSIX, - это сравнение файловых идентификаторов устройств, предоставляемых функцией stat (2) .

Perl имеет аналогичную функцию stat, как указал Жиль :

perl -e 'exit((stat($ARGV[0]))[0] != (stat($ARGV[1]))[0])' -- file1 file2

но «способ POSIX» заключается в использовании программы на C, например:

./checksamedev file1 file2

какой исходный код выглядит следующим образом:

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, char* argv[]) {
    struct stat s1, s2;
    if( argc==3 && lstat(argv[1], &s1)==0 && lstat(argv[2], &s2)==0 )
        return !(s1.st_dev == s2.st_dev);
    return 2;
}

Если идентификаторы устройств обоих файлов совпадают, они размещаются в одной файловой системе, и в этом случае приведенные выше команды возвращают 0 (другое значение в противном случае). Проверьте с echo $?.

Это хорошо работает с bind mounts, но, вероятно, не с сетевыми подключениями.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.