Comment puis-je "relier" beaucoup de liens symboliques brisés?


54

J'ai un arbre de répertoire qui a un tas de liens symboliques vers des fichiers sous /home... cependant, je me suis déplacé /homevers /mnt/homeet j'ai besoin d'un moyen de "relier" tous les liens symboliques. Une telle fonctionnalité existe-t-elle ou dois-je écrire un script pour le faire?

Par exemple, j'ai quelque chose comme ce qui suit:

[root@trees ~]# ls -l /mnt/home/someone/something
total 4264
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 a -> /home/someone/someotherthing/a
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 b -> /home/someone/someotherthing/b
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 c -> /home/someone/someotherthing/c
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 d -> /home/someone/someotherthing/d
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 e -> /home/someone/someotherthing/e

/mnt/home/someone/something/subdir:
total 4264
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 a -> /home/someone/someotherthing/subdir/a
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 b -> /home/someone/someotherthing/subdir/b
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 c -> /home/someone/someotherthing/subdir/c
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 d -> /home/someone/someotherthing/subdir/d
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 e -> /home/someone/someotherthing/subdir/e

Je veux une commande qui trouvera tous les liens symboliques et reliera aux mêmes endroits mais en dessous /mnt/homeau lieu de/home

Une telle commande existe-t-elle?

Réponses:


55

Il n'y a pas de commande pour recibler un lien symbolique, tout ce que vous pouvez faire est de le supprimer et d'en créer un autre. En supposant que vous ayez des utilitaires GNU (par exemple sous Linux non intégré ou Cygwin), vous pouvez utiliser le -lnameprimaire de findpour faire correspondre les liens symboliques par leur cible et readlinkpour lire le contenu du lien. Non testé:

find /mnt/home/someone/something -lname '/home/someone/*' \
     -exec sh -c 'ln -snf "/mnt$(readlink "$0")" "$0"' {} \;

Il serait préférable de rendre ces liens symboliques relatifs. Il existe un petit utilitaire pratique appelé symlinks(à l'origine par Mark Lords, maintenant maintenu par J. Brandt Buckley), présent dans de nombreuses distributions Linux. Avant le déplacement, ou après avoir restauré les liens valides comme ci-dessus, exécutez la symlinks -c /mnt/home/someone/somethingconversion de tous les liens symboliques absolus du répertoire spécifié en liens symboliques relatifs, à moins qu'ils ne franchissent une limite du système de fichiers.


Sans vouloir vous offenser, c'est une excellente solution, mais le remplacement de la chaîne par Bash pourrait probablement apporter un peu de magie au changement de chemin et serait plus facile.
0xC0000022L

@STATUS_ACCESS_DENIED Comment ça va? La seule opération de chaîne consiste à ajouter /mntun chemin à un chemin; vous n'avez besoin d'aucune opération de chaîne plus sophistiquée que la concaténation.
Gilles 'SO- arrête d'être méchant'

@ Gilles: désolé, je pensais plus à votre remarque avec les chemins relatifs. Pour une "traduction" exacte de votre exemple, vous avez évidemment raison.
0xC0000022L

13

Je sais que ce n’est pas exactement ce que l’auteur demande, mais il semble qu’ils aient déjà leur réponse; j’ajoute donc cette précision aux personnes qui, comme moi, tombent sur la question.

Ce qui suit devrait vous aider si une solution plus flexible est requise, par exemple avoir un ensemble de liens symboliques brisés qui peuvent être corrigés en remplaçant une partie des cibles du lien symbolique.

par exemple. Après un changement de nom d'utilisateur, remplacez l'ancien nom d'utilisateur par le nouveau nom d'utilisateur dans la cible de nombreux liens, une fois le déplacement effectué. Créez un script appelé replace-simlinks ci-dessous:

#!/bin/bash
link=$1
# grab the target of the old link
target=$(readlink -- "$1")

# replace the first occurrence of oldusername with newusername in the target string
target=${target/oldusername/newusername}

# Test the link creation
echo ln -s -- "$target" "$link"

# If the above echo shows the correct commands are being issued, then uncomment the following lines and run the command again
#rm $link
#ln -s "$target" "$link"

et appelez-le avec la commande suivante:

find /home/newusername/ -lname '/home/oldusername/*' -exec ~/bin/replace-simlinks {} \;

J'espère que cela aidera quelqu'un

edit: Merci Gilles pour le kickstart sur ce script et le conseil sur l’utilisation du script des liens symboliques pour rendre les liens relatifs.


1
Je trouve cette solution préférable car elle utilise une chaîne de remplacement, ce qui est utile dans les cas où vous devez modifier le nom d'un dossier au milieu du chemin. La solution est également assez facile à modifier pour effectuer des transformations plus complexes si nécessaire.
Gallaecio

Je recommanderais de citer les arguments en faveur de la substitution de chaîne, car cela doit être fait pour utiliser des barres obliques, par exemple pour le chemin dans la question de l'OP. target=${target/"/home"/"/mnt/home"}Très utile, cependant. Merci.
Walter Nissen

3

Créez en /hometant que lien symbolique vers /mnt/home, et tous les liens symboliques existants seront à nouveau valides.


2
Le montage lié a souvent tendance à être moins fragile que les liens symboliques dans les scénarios où les programmes sont conscients des liens symboliques et agissent différemment selon le fait ...
0xC0000022L
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.