Comment puis-je trouver tous les fichiers liés en dur sur un système de fichiers?

21

J'ai besoin de trouver tous les fichiers liés sur un système de fichiers donné. Par exemple, obtenir une liste de fichiers, chaque ligne contient des paires liées, ou des triplets, etc.

Je comprends plus ou moins comment le faire, il faut créer un dictionnaire tapé par inode pour tous les fichiers / répertoires d'un système de fichiers, exclure "." et les liens "..", puis les indodes avec plus d'un nom sont des liens physiques ... Mais j'espère qu'il existe peut-être une solution toute faite, ou que quelqu'un a déjà écrit un tel script.

haimg
la source

Réponses:

17

Vous pouvez exécuter la commande suivante:

find / -type f -printf '%n %p\n' | awk '$1 > 1{$1="";print}'

pour trouver tous les fichiers liés en dur.

Ou version @mbafford:

find / -type f -links +1 -printf '%i %n %p\n'
Gilles Quenot
la source
1
Merci, ce n'est pas exactement ce que je voulais, mais assez proche. Je peux ajouter '% i' pour imprimer les numéros d'inode puis trier / grouper par celui-ci ...
haimg
15
Vous pouvez éviter d'avoir à utiliser awk en utilisant la syntaxe "-links + n 'de find. Par exemple, pour trouver tous les fichiers avec au moins deux liens et imprimer les informations nécessaires:find / -type f -links +1 -printf '%i %n %p\n'
mbafford
que diriez-vous de passer par sort(+ uniq)? j'étais curieux alors j'ai essayé sur mon ordinateur principal (16 Go i5-2500k avec ssd). avec 2187757 fichiers ( find / -xdev -type f | wc) prend 12 secondes réelles lors du retour de 3820 fichiers / 570 inodes ( time sudo find / -xdev -type f -links +1 -printf "%i\n" | sort | uniq | wc). vous auriez besoin d'inclure le %n %ppour les fichiers réels comme je les ai pris pour compter les inodes.
north-bradley
17
find . -type f -links +1 2>/dev/null

donne une liste de tous les fichiers qui ont plus d'un lien, c'est-à-dire les fichiers auxquels il existe un lien dur. La boucle est alors relativement facile - une solution hacky si vous n'avez pas autant de fichiers serait

for i in $(find . -type f -links +1 2>/dev/null); do find -samefile $i | awk '{printf "%s ", $1}'; printf "\n"; done | sort | uniq

Mais j'espère sincèrement qu'il existe de meilleures solutions, par exemple en laissant le premier findappel imprimer les numéros d'inode puis en utilisant findl' -inumoption de pour afficher tous les fichiers associés à cet inode.

Claudius
la source
1
Aie! Cela analyse le système de fichiers encore et encore pour chaque fichier
lié en dur
1
Je n'ai pas prétendu que c'était rapide - et cela fonctionne en quelque sorte pour les petites arborescences de répertoires. Bien sûr, un bon index, qui pourrait être construit, par exemple, à partir de la sortie de find . -type f -printf '%i %p\n', permettrait de construire une solution beaucoup plus rapide.
Claudius
Et cela ne gère pas l'espace dans le chemin AFAIK.
Gilles Quenot
Pour la forboucle, ajuster IFS en conséquence fonctionnerait. Pour analyser la sortie de la commande find dans mon commentaire, déclarer tout ce qui se trouve entre le premier espace et la fin de la ligne comme nom de fichier devrait également fonctionner.
Claudius
1
@Sati: il garantit que les messages d'erreur sont supprimés (par exemple pour les dossiers auxquels vous n'avez pas accès, lost+foundetc.); ce qui est particulièrement important, si la sortie doit être traitée davantage comme dans la deuxième ligne.
DJCrashdummy
1

À mon humble avis, la meilleure façon est d'utiliser la ligne suivante (à coup sûr, vous devez remplacer /PATH/FOR/SEARCH/par ce que vous voulez rechercher):

find /PATH/FOR/SEARCH/ -xdev -printf '%i\t%n\t%p\n' | fgrep -f <(find . -xdev -printf '%i\n' | sort -n | uniq -d) | sort -n

cela analyse le système de fichiers une seule fois, affiche l'inode, le nombre de liens physiques et le chemin des fichiers avec plus d'un lien physique et les trie en fonction de l'inode.

si vous êtes ennuyé par les messages d'erreur pour les dossiers que vous n'êtes pas autorisé à lire, vous pouvez étendre la ligne à ceci:

find /PATH/FOR/SEARCH/ -xdev -printf '%i\t%n\t%p\n' 2> /dev/null | fgrep -f <(find . -xdev -printf '%i\n' 2> /dev/null | sort -n | uniq -d) | sort -n
DJCrashdummy
la source