Mise à jour par lots des liens symboliques récursivement

12

J'ai une application web qui a un tas de liens symboliques dans les sous-répertoires tout au long. J'ai besoin de déplacer l'application vers une autre structure de répertoires et je dois mettre à jour tous les liens symboliques pour pointer vers le nouveau chemin. Par exemple:

Ancien Dir: /home/user/public_html/dev
Nouveau Dir: /home/user/public_html/qa
Ancien Symlink: /home/user/public_html/qa/multisites/slave01/images -> /home/user/public_html/dev/images
Nouveau Symlink:/home/user/public_html/qa/multisites/slave01/images -> /home/user/public_html/qa/images

Le problème est qu'il y en a beaucoup dispersés dans divers répertoires. Comment rechercher récursivement à partir de la racine et recréer tous les liens symboliques pointant vers /dev/avec /qa/?

ggutenberg
la source

Réponses:

16

Cette commande bash devrait le faire pour vous:

find /home/user/public_html/qa/ -type l -lname '/home/user/public_html/dev/*' -printf 'ln -nsf "$(readlink "%p" | sed s/dev/qa/)" "$(echo "%p" | sed s/dev/qa/)"\n' > script.sh

Il utilise findpour identifier tous les fichiers du qarépertoire qui sont des liens symboliques avec une cible qui se trouve dans le devrépertoire, et pour chacun, il imprime une commande bash qui remplacera le lien par un lien vers le chemin équivalent dans qa/. Après avoir exécuté cela, exécutez simplement le script généré avec

bash script.sh

Vous pouvez d'abord l'examiner manuellement pour vous assurer qu'il fonctionne.

Voici une version plus détaillée de la findcommande ci-dessus pour une lecture plus facile (bien que je ne l'écrirais pas nécessairement de cette façon dans la pratique):

SRC_DIR="/home/user/public_html/qa"
OLD_TARGET="/home/user/public_html/dev"
SUB="s/dev/qa/"

find $SRC_DIR -type l \
  -lname "$OLD_TARGET/*" -printf \
  'ln -nsf "$(readlink "%p"|sed $SUB)" "$(echo "%p"|sed $SUB)"\n'\
 > script.sh
David Z
la source
Cela crée un script.sh vide. Et exécuter la commande find comme ceci: find /home/user/public_html/qa/ -type l -lname '/home/user/public_html/dev/*' ne produit rien.
ggutenberg
Vous vous souveniez de changer les chemins d'accès en ceux réels sur votre système de fichiers, non? Que se passe-t-il si vous courez juste find /home/usr/public_html/qa/ -type l? Si cela ne trouve pas les liens, quelque chose de très bizarre se passe avec votre système.
David Z
Oui, " find /home/user/public_html/qa/ -type l" affiche les liens. Mais l'ajout du paramètre -lname ne produit rien.
ggutenberg
En fait, lors de tests supplémentaires, il semble que cela fonctionne. Je ne sais pas ce que je faisais mal hier, mais ça va maintenant. Merci.
ggutenberg
Huh, bizarre. Eh bien, si jamais vous découvrez ce qui ne va pas, mettez un commentaire ici. Je suis curieux.
David Z
5

Dans le cas où quelqu'un d'autre trouverait ceci lors de la recherche d'une solution: Créez un fichier nommé "linkmod.sh" contenant:

#!/bin/sh
PATTERN1=`echo "$2"`
PATTERN2=`echo "$3"`
LINKNAME=`echo "$1"`
OLDTARGET=`readlink "$1"`
NEWTARGET=`echo "$OLDTARGET" \
| sed -e 's/'"$PATTERN1"'/'"$PATTERN2"'/'`
echo ln -nsf "$NEWTARGET" "$LINKNAME"

et courir

find . -type l -print0 | xargs -0IX echo linkmod.sh X "pattern1" "pattern2"

Vous pouvez ofc utiliser l'option -lname dans find si nécessaire.

REMARQUE: vous devez utiliser 2x \ dans les modèles avant tous les caractères qui nécessitent \ in sed, car echo en supprime un. Par exemple

find . -type l -print0 | xargs -0IX echo linkmod.sh X "folder\\ name\\/file" "folder2\\ name\\/file"

Supprimez le echode la dernière ligne si les commandes ln sont correctes.

rknC
la source
Peut - être bon de préciser que les deux echodans la dernière ligne du scénario et echodans la find .. | xargs .. linkmod.sh ...commande elle - même à la fois doivent être enlevés.
Kyle Strand
2

J'ai créé un script bash link_rename.shpour renommer récursivement les liens symboliques dans un répertoire donné

#! /bin/bash

DIR=$1
OLD_PATTERN=$2
NEW_PATTERN=$3

while read -r line
do
    echo $line
    CUR_LINK_PATH="$(readlink "$line")"
    NEW_LINK_PATH="$CUR_LINK_PATH"  
    NEW_LINK_PATH="${NEW_LINK_PATH/"$OLD_PATTERN"/"$NEW_PATTERN"}"
    rm "$line"
    ln -s "$NEW_LINK_PATH" "$line"
done <<< $(find "$DIR" -type l)

Il peut être exécuté comme link_rename.sh /home/human/dir link1 link2

Le script a 3 arguments:

  1. Le répertoire dans lequel vous souhaitez effectuer le renommage par lots des liens symboliques
  2. L'ancien modèle. Voici link1l'ancien modèle qui sera remplacé
  3. Le nouveau modèle. Voici link2le nouveau modèle avec lequel link1sera remplacé

Le script lit récursivement tous les liens symboliques du répertoire à l'aide find "$DIR" -type l et le traite ligne par ligne.

$line est le lien symbolique qui doit être renommé

CUR_LINK_PATH est l'ancien chemin

NEW_LINK_PATH est obtenu en effectuant le remplacement de chaîne dans l'ancien chemin de liaison.

L'ancien lien symbolique est supprimé et un nouveau lien symbolique est créé à l'aide de ln -s "$NEW_LINK_PATH" "$line"

Akhil Mohan
la source
0

J'ai fini par écrire un script PHP en ligne de commande qui semble faire l'affaire.

<?php
//Run via command-line
$dir = new RecursiveDirectoryIterator('.');
foreach(new RecursiveIteratorIterator($dir) as $file) {
    //$link = readlink($file);
    if(is_link($file)) {
        $old_link = readlink($file);
        $new_link = str_ireplace("/joomla/", "/qa/", $old_link);
        if($new_link != $old_link) {
            exec('rm "'.$file.'"');
            exec('ln -fs "'.$new_link.'" "'.$file.'"');
            $new_link = readlink($file);
            if($new_link == $old_link) {
                echo $file."\t".$old_link."\t".$new_link."\n";
            }
        }
    }
}
?>
ggutenberg
la source