Compruebe si 2 directorios están alojados en la misma partición en Linux

9

¿Cómo puedo verificar si /my/direstá en la misma partición que /?

Esto es para la integración dentro de un script. Los montajes de unión deben manejarse correctamente. Las soluciones compatibles con POSIX son bienvenidas.

Totor
fuente
"Las monturas de unión deben manejarse correctamente". ¿Pero qué consideras correcto? Su pregunta puede ser interpretada de cualquier manera.
Gilles 'SO- deja de ser malvado'
@Gilles En el título original que escribí "alojado" en lugar de "montado", alguien editó añadiendo confusión en mi humilde opinión. Sin embargo, mi cuerpo de preguntas es claro: "en la misma partición", es decir, en la misma partición física, sea cual sea la ruta o el punto de montaje utilizado para acceder a los dos archivos / directorios.
Totor

Respuestas:

6

Puede verificar esto con stat:

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

Muestra el número de dispositivo y dónde se montó su directorio.


fuente
1
Bien, pero el statcomando de shell no es POSIX ...
Totor
¿No? ¿Cómo lo sabes?
No en esta lista .
Totor
Oh mi error. Pero la próxima vez muestre este enlace de antemano.
5

El siguiente comando proporciona un nombre único para el punto de montaje que contiene el archivo $file:

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

Esto funciona en cualquier sistema POSIX . La -Popción impone un formato predecible; El primer campo de la segunda línea es el "nombre del sistema de archivos". Por lo tanto, para verificar dos archivos están bajo el mismo punto de montaje:

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

O, para guardar un par de invocaciones de procesos:

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

Algunos sistemas operativos pueden tener espacios en los nombres de volumen. No hay una forma completamente confiable de analizar la dfsalida en este caso.

Debajo del capó, puede identificar el sistema de archivos que contiene un archivo por el st_devcampo devuelto por stat. No hay una forma portátil de hacer esto desde un script de shell. Algunos sistemas tienen una statutilidad, pero su sintaxis varía:

  • En Linux no incorporado, Cygwin u otros sistemas con GNU coreutils, statinforma el st_devcampo cuando se invoca como stat -c %D -- "$file".
  • Algunas instalaciones de BusyBox incluyen una statque es compatible con GNU coreutils. Otros tienen statsin la %copción; puede usarlo, stat -t -- "$file" | awk '{print $8}'pero esto solo funciona si el nombre del archivo no contiene espacios en blanco, o si stat -t -- "$file" | awk 'END {print $(NF-8)}'hace frente a nombres de archivo arbitrarios pero no a futuras adiciones de campos a la statsalida.
  • Los sistemas BSD tienen una statutilidad diferente que requiere stat -f %d -- "$file".
  • Solaris, AIX y otros no tienen statutilidad.

Si Perl está disponible, puede usar

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

y para hacer la comparación:

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

Tenga en cuenta que hay algunos casos de esquina donde el resultado deseado no está claro. Por ejemplo, con los montajes de enlace de Linux, after mount --bind /foo /bar, /fooy /barse consideran el mismo sistema de archivos. Siempre es posible que los dos archivos estén ubicados en el mismo dispositivo, pero nunca lo sabrá: por ejemplo, si los archivos están en dos montajes de red diferentes, el cliente no tiene forma de saber si el servidor está exportando diferentes sistemas de archivos.

Si los archivos son directorios y puede escribir en ellos, otro método es crear un archivo temporal e intentar crear un enlace rígido. Este informa un resultado negativo en los montajes de enlace de Linux.

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"
Gilles 'SO- deja de ser malvado'
fuente
Problema: dfno siempre da el nombre del dispositivo, pero en algún momento un enlace simbólico a ella como /dev/disk/by-uuid/ca09b761-ae1b-450f-8a46-583327b48fb4lo que dfno es fiable. La única opción confiable hasta ahora es utilizar una statsolución basada en.
Totor
@ Motor Eso no importa: cualquier nombre que dfinforme para el dispositivo, es coherente entre las dos invocaciones, por lo que está bien para una comparación.
Gilles 'SO- deja de ser malvado'
No, no funciona, lo probé. En Debian Wheezy aquí, un solo dfinforme /dev/sda6y /dev/disk/by-uuid/ca09b..., ambos se refieren al mismo dispositivo, pero diferentes puntos de montaje. La prueba de comparación de cadenas obviamente falla al intentar con archivos de cada punto de montaje.
Totor
@ Motor Normalmente no puede tener el mismo dispositivo de bloqueo montado dos veces. Como indico en mi respuesta, hay casos de esquina como monturas de unión que pueden o no ser reportados como distintos.
Gilles 'SO- deja de ser malvado'
Sin embargo, funciona perfectamente en Debian Squeeze y Wheezy: mount /dev/sda6 /mnt1seguido de mount /dev/sda6 /mnt2trabajos como un encanto. cat /proc/mountsestá bien con eso. Sin embargo, solo desde Wheezy /dev/disk/by-uuid/ca09b...se muestra dfcomo el dispositivo para el sistema de archivos raíz. Los intentos adicionales de montarlo usando este enlace simbólico o la UUID=ca09b...sintaxis de montaje no terminan mostrando nada más que /dev/sda6en df(no sé cómo reproducir lo que hizo durante el proceso de arranque, pero esa no es la preocupación aquí).
Totor
4
test $(df -P $path1 $path2 | awk '{if (NR!=1) {print $6}}' | uniq | wc -l) -eq 1

Funciona con cualquier número de caminos.

n.st
fuente
Analizando la salida del dfes no siempre una buena idea .
Joseph R.
1
@ Motor Estoy comprobando el punto de montaje ( $6), no el nombre del dispositivo ( $1), por lo que no debería ser un problema.
n.st
1
@JosephR Es lo mejor que hay en POSIX. n.st: ¿por qué no verificar el primer campo? No importa qué ruta se utilizó para acceder al dispositivo, si es el mismo punto de montaje, la salida será coherente.
Gilles 'SO- deja de ser malvado'
Esto no funciona con montajes de unión.
Totor
0

La mejor solución infalible disponible en POSIX es la comparación de las ID de dispositivo de los archivos proporcionadas por la función stat (2) .

Perl tiene una función estadística similar a la que Gilles señaló :

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

pero la "forma POSIX" es usar un programa en C como:

./checksamedev file1 file2

cuyo código fuente es el siguiente:

#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;
}

Si las ID de dispositivo de ambos archivos son iguales, se alojan en el mismo sistema de archivos, en cuyo caso, los comandos anteriores devuelven 0 (de lo contrario, otro valor). Consulte con echo $?.

Esto funciona bien con los montajes de enlace, pero probablemente no lo hará con los montajes de red.

Totor
fuente