Deux fichiers sont-ils liés en dur?

27

Comment savoir si deux fichiers sont liés en dur à partir de la ligne de commande? par exemple quelque chose lier ceci:

$ ls
fileA fileB fileC

$ is-hardlinked fileA fileB
yes

$ is-hardlinked fileA fileC
no
Vincent Scheib
la source

Réponses:

37

Sur la plupart des systèmes de fichiers¹, un fichier est uniquement déterminé par son numéro d' inode , il vous suffit donc de vérifier si les deux fichiers ont le même numéro d'inode et se trouvent sur le même système de fichiers.

Ash, ksh, bash et zsh ont une construction qui vérifie pour vous: l'opérateur d'égalité de fichier -ef.

[ fileA -ef fileB ] && ! [ fileA -ef fileC ]

Pour les cas plus avancés, ls -i /path/to/filerépertorie le numéro d'inode d'un fichier. df -P /path/to/filemontre sur quel système de fichiers se trouve le fichier (si deux fichiers se trouvent dans le même répertoire, ils se trouvent sur le même système de fichiers). Si votre système dispose de la statcommande, elle peut probablement afficher les numéros d'inode et de système de fichiers ( statvarie d'un système à l'autre, consultez votre documentation). Si vous voulez un rapide coup d'œil sur les liens durs à l'intérieur d'un répertoire, essayez ls -i | sort(éventuellement canalisé vers awk ).

¹ Tous les systèmes de fichiers Unix natifs, et quelques autres tels que NTFS, mais peut-être pas des cas exotiques comme CramFS.

Gilles 'SO- arrête d'être méchant'
la source
Et certainement pas sur quoi que ce soit basé sur FAT, où il serait détecté comme un fichier "réticulé".
Ignacio Vazquez-Abrams
4
Notez que fileA -ef fileBrenvoie également 0(succès) si fileAest un lien symbolique vers fileB, ou vice versa, ou les deux sont liés au même fichier.
janmoesen
comment exécutez-vous réellement la commande que vous avez suggérée? J'ai essayé [.bashrc -ef .bash / .bashrc] et ses variantes, mais cela n'a pas vraiment fonctionné.
Charlie Parker
@CharlieParker [ .bashrc -ef .bash/.bashrc ]est correct. Sans contexte, bien sûr, je n'ai aucune idée pourquoi cela «n'a pas vraiment fonctionné» - vous pourriez comparer les mauvais fichiers, vous pourriez ne pas vérifier correctement le résultat, vous pourriez utiliser un shell sans -ef, ...
Gilles 'SO- arrêtez d'être méchant'
2
@CharlieParker La commande est en fait [et est un synonyme de test. Mais man [ou man testvous donnera la page de manuel de la commande externe, alors que presque tous les shell ont une commande intégrée avec des options légèrement différentes, vous devez donc rechercher celle-ci dans le manuel de votre shell.
Gilles 'SO- arrête d'être méchant'
4
function is-hardlinked() {
    r=yes
    [ "`stat -c '%i' $1`" != "`stat -c '%i' $2`" ] && r=no
    echo $r
}
x-way
la source
6
Notez que cela peut être un faux positif si les deux fichiers se trouvent sur des systèmes de fichiers différents mais ont le même inode. Vous devez également tester le numéro de périphérique ( stat -c %d). Et si vous êtes sous Linux (compte tenu de votre statcommande), votre shell a le droit [ fileA -ef fileB ]de faire tout cela directement. De plus, votre commande rompt gratuitement avec les noms de fichiers contenant des espaces ou \[?*, ou commence par -: mettez toujours des guillemets autour des commandes susbtitutions ( "$(stat -c %i -- "$1")").
Gilles 'SO- arrête d'être méchant'
1
Pourquoi utiliseriez-vous un tas de constructions lourdes mais portables, puis le functionmot - clé abjectement non portable avec un nom de fonction qui (à cause de la présence d'un tiret) viole les conventions POSIX sur les noms autorisés?
Charles Duffy
Vous avez oublié de citer votre $1et $2. Vous souhaiterez peut-être également utiliser la $()syntaxe au lieu des backticks car les crochets indiquent clairement où la commande commence et où elle se termine et l'imbrication est plus simple.
josch
3

Comme le suggère la première affiche, vous pouvez écrire un script basé sur quelque chose comme ça sous Linux:

stat -c '%i' fileA fileB fileC
Pas maintenant
la source
4
Cela ne suffit pas: vous obtiendrez le même numéro pour les deux fichiers s'ils se trouvent sur des systèmes de fichiers différents mais ont le même inode. Vous devez également tester le numéro de périphérique ( stat -c %d). Et si vous êtes sous Linux (compte tenu de votre statcommande), votre shell a le droit [ fileA -ef fileB ]de faire tout cela directement.
Gilles 'SO- arrête d'être méchant'
0

Avec GNU find(1)version 4.2.11 ou plus récente, vous pouvez également utiliser ceci:

if [ "yes" = "$(find fileA -samefile fileB -exec echo yes \;)" ]; then
    echo yes
else
    echo no
fi

Si fileAest le même fichier que fileBpuis findimprimera « oui » et la condition devient vraie.

Contrairement à l'utilisation de l'opérateur d'égalité de fichiers, -efcela engendrera un nouveau processus.

josch
la source