Vérifiez si 2 répertoires sont hébergés sur la même partition sous Linux


9

Comment puis-je vérifier si se /my/dirtrouve sur la même partition que /?

C'est pour l'intégration dans un script. Les montures de liaison doivent être manipulées correctement. Les solutions compatibles POSIX sont les bienvenues.


"Les montures Bind doivent être manipulées correctement." Mais que considérez-vous correct? Votre question peut être interprétée dans les deux sens.
Gilles 'SO- arrête d'être méchant'

@Gilles Dans le titre original, j'ai écrit "hébergé" au lieu de "monté", quelqu'un a édité en ajoutant la confusion à mon humble avis. Pourtant, mon corps de question est clair: "sur la même partition", c'est-à-dire sur la même partition physique, quel que soit le chemin ou le point de montage utilisé pour accéder aux deux fichiers / répertoires.
Totor

Réponses:


6

Vous pouvez vérifier cela avec stat:

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

Vous indique le numéro de périphérique et l'endroit où votre répertoire a été monté.


1
Sympa, mais la statcommande shell n'est pas POSIX ...
Totor

Non? Comment le sais-tu?

Pas dans cette liste .
Totor

Oh, ma mauvaise. Mais la prochaine fois montrez ce lien à l'avance.

5

La commande suivante donne un nom unique au point de montage contenant le fichier $file:

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

Cela fonctionne sur n'importe quel système POSIX . L' -Poption impose un format prévisible; le premier champ de la deuxième ligne est le «nom du système de fichiers». Ainsi, pour vérifier que deux fichiers se trouvent sous le même point de montage:

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

Ou, pour enregistrer quelques appels de processus:

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

Quelques systèmes d'exploitation peuvent avoir des espaces dans les noms de volume. Il n'y a aucun moyen complètement fiable d'analyser la dfsortie dans ce cas.

Sous le capot, vous pouvez identifier le système de fichiers contenant un fichier par le st_devchamp renvoyé par stat. Il n'y a aucun moyen portable de le faire à partir d'un script shell. Certains systèmes ont un statutilitaire, mais sa syntaxe varie:

  • Sur Linux non intégré, Cygwin ou d'autres systèmes avec des coreutils GNU, statsignale le st_devchamp lorsqu'il est appelé en tant que stat -c %D -- "$file".
  • Certaines installations BusyBox incluent un statqui est compatible avec GNU coreutils. D'autres ont statsans %coption; vous pouvez utiliser, stat -t -- "$file" | awk '{print $8}'mais cela ne fonctionne que si le nom de fichier ne contient pas d'espaces, ou stat -t -- "$file" | awk 'END {print $(NF-8)}'qui accepte des noms de fichiers arbitraires mais pas avec de futurs ajouts de champs à la statsortie.
  • Les systèmes BSD ont un statutilitaire différent qui nécessite stat -f %d -- "$file".
  • Solaris, AIX et d'autres n'ont aucun statutilitaire.

Si Perl est disponible, vous pouvez utiliser

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

et pour faire la comparaison:

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

Notez qu'il existe des cas d'angle où le résultat souhaité n'est pas clair. Par exemple, avec pochettes de protection se lient de Linux, après mount --bind /foo /bar, /fooet /barsont considérés comme le même système de fichiers. Il est toujours possible que les deux fichiers se trouvent réellement sur le même appareil, mais vous ne le saurez jamais: par exemple, si les fichiers se trouvent sur deux montages réseau différents, le client n'a aucun moyen de savoir si le serveur exporte des systèmes de fichiers différents.

Si les fichiers sont des répertoires et que vous pouvez y écrire, une autre méthode consiste à créer un fichier temporaire et à tenter de créer un lien dur. Celui-ci signale un résultat négatif sur les montages de liaison 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"

Problème: dfne donne pas toujours le nom de l'appareil, mais parfois un lien symbolique vers celui-ci, comme /dev/disk/by-uuid/ca09b761-ae1b-450f-8a46-583327b48fb4rendre dfnon fiable. Jusqu'à présent, la seule option fiable consiste à utiliser une statsolution basée sur.
Totor

@Totor Cela n'a pas d'importance: quel que soit le nom dfsignalé pour le périphérique, il est cohérent entre les deux invocations, donc c'est correct pour une comparaison.
Gilles 'SO- arrête d'être méchant'

Non, ça ne marche pas, je l'ai testé. Sur Debian Wheezy ici, un seul dfrapport /dev/sda6et /dev/disk/by-uuid/ca09b..., tous deux faisant référence au même périphérique, mais à des points de montage différents. Le test de comparaison de chaînes échoue évidemment lors de la tentative avec des fichiers de chaque point de montage.
Totor

@Totor Normalement, vous ne pouvez pas avoir le même périphérique de bloc monté deux fois. Comme je l'indique dans ma réponse, il existe des cas d'angle tels que les montures de reliure qui peuvent ou non être signalés comme distincts.
Gilles 'SO- arrête d'être méchant'

Pourtant, cela fonctionne parfaitement sur Debian Squeeze et Wheezy: mount /dev/sda6 /mnt1suivi par des mount /dev/sda6 /mnt2œuvres comme un charme. cat /proc/mountsest bien avec ça. Cependant, ce n'est que depuis Wheezy qui /dev/disk/by-uuid/ca09b...est affiché en dftant que périphérique pour le système de fichiers racine. D'autres tentatives de montage à l'aide de ce lien sim ou de la UUID=ca09b...syntaxe de montage ne finissent par afficher autre chose que /dev/sda6dans df(je ne sais pas comment reproduire ce qu'il a fait pendant le processus de démarrage, mais ce n'est pas le problème ici).
Totor

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

Fonctionne avec un nombre illimité de chemins.


L'analyse de la sortie de dfn'est pas toujours une bonne idée .
Joseph R.

1
@Totor Je vérifie le point de montage ( $6), pas le nom du périphérique ( $1), donc cela ne devrait pas être un problème.
n.st

1
@JosephR C'est le meilleur de POSIX. n.st: pourquoi ne pas cocher le premier champ? Peu importe le chemin d'accès utilisé pour accéder à l'appareil, s'il s'agit du même point de montage, la sortie sera cohérente.
Gilles 'SO- arrête d'être méchant'

Cela ne fonctionne pas avec les montures de liaison.
Totor

0

La meilleure solution infaillible disponible dans POSIX est la comparaison des ID de périphérique des fichiers fournis par la fonction stat (2) .

Perl a une même fonction stat que Gilles a fait remarquer :

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

mais la "façon POSIX" consiste à utiliser un programme C comme:

./checksamedev file1 file2

dont le code source est le suivant:

#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 les ID de périphérique des deux fichiers sont égaux, ils sont hébergés sur le même système de fichiers, auquel cas, les commandes ci-dessus renvoient 0 (une autre valeur sinon). Vérifiez avec echo $?.

Cela fonctionne bien avec les montages de liaison, mais probablement pas avec les montages réseau.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.