Как я могу проверить, /my/dir
находится ли на том же разделе, что и /
?
Это для интеграции внутри скрипта. Крепления должны быть обработаны правильно. POSIX-совместимые решения приветствуются.
Как я могу проверить, /my/dir
находится ли на том же разделе, что и /
?
Это для интеграции внутри скрипта. Крепления должны быть обработаны правильно. POSIX-совместимые решения приветствуются.
Ответы:
Вы можете проверить это с помощью stat:
$ stat -c '%d %m' /proc/sys/
3 /proc
Показывает номер устройства и где был установлен ваш каталог.
stat
оболочки не POSIX ...
Следующая команда дает уникальное имя для точки монтирования, содержащей файл $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
утилита, но ее синтаксис различен:
stat
сообщает st_dev
поле при вызове как stat -c %D -- "$file"
.stat
который совместим с GNU coreutils. Другие имеют stat
без %c
опции; Вы можете использовать, stat -t -- "$file" | awk '{print $8}'
но это работает только в том случае, если имя файла не содержит пробелов, или stat -t -- "$file" | awk 'END {print $(NF-8)}'
которое справляется с произвольными именами файлов, но не с будущими добавлениями полей к stat
выводу.stat
утилиту, которая требует stat -f %d -- "$file"
.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
решения на основе.
df
сообщалось для устройства, оно согласовано между двумя вызовами, поэтому для сравнения все в порядке.
df
отчет /dev/sda6
и /dev/disk/by-uuid/ca09b...
, оба ссылаются на одно и то же устройство, но разные точки монтирования. При сравнении файлов из каждой точки монтирования проверка сравнения строк явно не проходит.
mount /dev/sda6 /mnt1
за ним следует mount /dev/sda6 /mnt2
работа, как шарм. cat /proc/mounts
хорошо с этим. Тем не менее, только с тех пор, как Wheezy /dev/disk/by-uuid/ca09b...
отображается df
как устройство для корневой файловой системы. Дальнейшие попытки установить его с помощью этого SimLink или UUID=ca09b...
смонтировать синтаксис не до конца , показывая что - нибудь еще , чем /dev/sda6
в df
(я не знаю , как воспроизвести то , что это было сделано во время процесса загрузки, но это не забота здесь).
test $(df -P $path1 $path2 | awk '{if (NR!=1) {print $6}}' | uniq | wc -l) -eq 1
Работает с любым количеством путей.
df
является не всегда хорошей идеей .
$6
), а не имя устройства ( $1
), так что это не должно быть проблемой.
Лучшее надежное решение, доступное в 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, но, вероятно, не с сетевыми подключениями.