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

9

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

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

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

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

n.st
источник
Синтаксический вывод 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, но, вероятно, не с сетевыми подключениями.

Totor
источник