web-dev-qa-db-fra.com

Linux: Trouvez tous les liens symboliques d'un fichier 'original' donné? (reverse 'readlink')

Considérez l'extrait de ligne de commande suivant: 

$ cd /tmp/
$ mkdir dirA
$ mkdir dirB
$ echo "the contents of the 'original' file" > orig.file
$ ls -la orig.file 
-rw-r--r-- 1 $USER $USER 36 2010-12-26 00:57 orig.file

# create symlinks in dirA and dirB that point to /tmp/orig.file:

$ ln -s $(pwd)/orig.file $(pwd)/dirA/
$ ln -s $(pwd)/orig.file $(pwd)/dirB/lorig.file
$ ls -la dirA/ dirB/
dirA/:
total 44
drwxr-xr-x  2 $USER $USER  4096 2010-12-26 00:57 .
drwxrwxrwt 20 root          root          36864 2010-12-26 00:57 ..
lrwxrwxrwx  1 $USER $USER    14 2010-12-26 00:57 orig.file -> /tmp/orig.file

dirB/:
total 44
drwxr-xr-x  2 $USER $USER  4096 2010-12-26 00:58 .
drwxrwxrwt 20 root          root          36864 2010-12-26 00:57 ..
lrwxrwxrwx  1 $USER $USER    14 2010-12-26 00:58 lorig.file -> /tmp/orig.file

À ce stade, je peux utiliser readlink pour voir ce qui est "original" (eh bien, je suppose que le terme habituel est "cible" ou "source", mais ceux dans mon esprit peuvent être aussi opposés, donc je Je vais juste l'appeler 'original') fichier des liens symboliques, c'est à dire.

$ readlink -f dirA/orig.file 
/tmp/orig.file
$ readlink -f dirB/lorig.file 
/tmp/orig.file

... Cependant, ce que j'aimerais savoir, c'est: y a-t-il une commande que je pourrais exécuter sur le fichier "original" et trouver tous les liens symboliques qui le dirigent? En d'autres termes, quelque chose comme (pseudo):

$ getsymlinks /tmp/orig.file
/tmp/dirA/orig.file 
/tmp/dirB/lorig.file

Merci d'avance pour vos commentaires, 

À votre santé!

45
sdaau

Je n'ai pas vu de commande pour cela et ce n'est pas une tâche facile, car le fichier cible ne contient aucune information sur les fichiers source qui le désignent.

Ceci est similaire aux liens "durs" mais au moins ceux-ci sont toujours sur le même système de fichiers afin que vous puissiez faire un find -inode pour les lister. Les liens symboliques sont plus problématiques car ils peuvent traverser des systèmes de fichiers.

Je pense que ce que vous allez devoir faire, c'est essentiellement exécuter un ls -al sur chaque fichier de votre hiérarchie entière et utiliser grep pour rechercher -> /path/to/target/file.

Par exemple, en voici une que j'ai exécutée sur mon système (formatée pour la lisibilité - ces deux dernières lignes sont en fait sur one line dans la sortie réelle):

pax$ find / -exec ls -ald {} ';' 2>/dev/null | grep '\-> /usr/share/applications'
lrwxrwxrwx 1 pax pax 23 2010-06-12 14:56 /home/pax/applications_usr_share
                                         -> /usr/share/applications
30
paxdiablo

À l’aide de GNU find, les fichiers liés durement ou par un lien symbolique à un fichier seront trouvés:

find -L /dir/to/start -samefile /tmp/orig.file
123
Dennis Williamson

Les liens symboliques ne suivent pas ce qui pointe vers une destination donnée. Vous ne pouvez donc rien faire de mieux que de vérifier chaque lien symbolique pour voir s'il pointe vers la destination souhaitée, comme

for i in *; do
    if [ -L "$i" ] && [ "$i" -ef /tmp/orig.file ]; then
        printf "Found: %s\n" "$i"
    fi
done
2
jilles

Voici ce que je suis venu avec. Je le fais sous OS X, qui n'a pas readlink -f; j'ai donc dû utiliser une fonction d'assistance pour le remplacer. Si vous avez un readlink -f correct, vous pouvez l'utiliser à la place. De plus, l'utilisation de while ... done < <(find ...) n'est pas strictement nécessaire dans ce cas, un simple find ... | while ... done fonctionnerait; mais si vous avez déjà voulu faire quelque chose comme définir une variable dans la boucle (comme un nombre de fichiers correspondants), la version du tube échouera car la boucle while s'exécutera dans un sous-shell. Enfin, notez que j’utilise find ... -type l pour que la boucle ne s’exécute que sur des liens symboliques et non sur d’autres types de fichiers.

# Helper function 'cause my system doesn't have readlink -f
readlink-f() {
    orig_dir="$(pwd)"
    f="$1"
    while [[ -L "$f" ]]; do
        cd "$(dirname "$f")"
        f="$(readlink "$(basename "$f")")"
    done
    cd "$(dirname "$f")"
    printf "%s\n" "$(pwd)/$(basename "$f")"
    cd "$orig_dir"
}

target_file="$(readlink-f "$target_file")" # make sure target is normalized

while IFS= read -d '' linkfile; do
    if [[ "$(readlink-f "$linkfile")" == "$target_file" ]]; then 
        printf "%s\n" "$linkfile"
    fi
done < <(find "$search_dir" -type l -print0)
0
Gordon Davisson

Inspiré par le commentaire de Gordon Davisson. Cela ressemble à une autre réponse, mais j’ai obtenu les résultats souhaités avec exec. J'avais besoin de quelque chose qui puisse trouver des liens symboliques sans savoir où se trouvait le fichier d'origine.

find / -type l -exec ls -al {} \; | grep -i "all_or_part_of_original_name"
0
Jer