シンボリックリンクの再帰的なバッチ更新


12

サブディレクトリにシンボリックリンクがたくさんあるウェブアプリがあります。アプリを別のディレクトリ構造に移動する必要があります。また、新しいパスを指すようにすべてのシンボリックリンクを更新する必要があります。例えば:

古いディレクトリ:/home/user/public_html/dev
新しいディレクトリ:/home/user/public_html/qa
古いシンボリックリンク:/home/user/public_html/qa/multisites/slave01/images -> /home/user/public_html/dev/images
新しいシンボリックリンク:/home/user/public_html/qa/multisites/slave01/images -> /home/user/public_html/qa/images

問題は、これらの多くがさまざまなディレクトリ全体に散在していることです。どのように私は再帰的にルートから検索し、シンボリックリンクを指しているすべての再作成することができます/dev/との/qa/

回答:


16

このbashコマンドはあなたのためにそれをするはずです:

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

ディレクトリfind内のqaターゲットとのシンボリックリンクであるディレクトリ内のすべてのファイルを識別するために使用しdev、それぞれについて、リンクをの同等のパスへのリンクに置き換えるbashコマンドを出力しqa/ます。これを実行した後、生成されたスクリプトを実行してください

bash script.sh

最初に手動で調べて、正常に機能することを確認することもできます。

find読みやすくするために、上記のコマンドのより詳細なバージョンを次に示します(実際には、必ずしもこのように記述する必要はありません)。

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

これにより、空のscript.shが作成されます。そして、findコマンドをそのまま実行すると、 find /home/user/public_html/qa/ -type l -lname '/home/user/public_html/dev/*' 何も出力されません。
guutenberg

パスをファイルシステム上の実際のパスに変更することを覚えていますか?ちょうど走るとどうなるのfind /home/usr/public_html/qa/ -type l?それでもリンクが見つからない場合は、システムで非常に奇妙なことが起こっています。
David Z

はい、「find /home/user/public_html/qa/ -type l」はリンクを出力します。しかし、-lnameパラメータを追加すると、何も出力されません。
guutenberg

実際、さらなるテストでは、これは機能しているようです。昨日私が何をしていたかわからないが、今は大丈夫だ。ありがとう。
guutenberg

あ、変。まあ、何がうまくいかなかったのか分かったら、ここにコメントを書いてください。私は興味がある。
David Z

5

他の誰かが解決策を検索しているときにこれを見つけた場合:「linkmod.sh」という名前のファイルを作成します。

#!/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"

そして走る

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

必要に応じて、検索で-lnameオプションを使用できます。

注:エコーによって1つ削除されるため、sedで\を必要とする文字の前にパターンで2x \を使用する必要があります。例えば

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

echolnコマンドが正しい場合は、最後の行からを削除します。


スクリプトのecho最終行のinとコマンド自体のinの両方を削除する必要があることを明確にするとよいでしょう。echofind .. | xargs .. linkmod.sh ...
カイルストランド2017

2

link_rename.sh特定のディレクトリでシンボリックリンクの名前を再帰的に変更するためのbashスクリプトを作成しました

#! /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)

次のように実行できます link_rename.sh /home/human/dir link1 link2

スクリプトには3つの引数があります。

  1. シンボリックリンクの一括名前変更を実行するディレクトリ
  2. 古いパターン。ここでlink1置き換えられます古いパターンがあります
  3. 新しいパターン。ここではlink2これで新しいパターンでlink1置き換えられますが

スクリプトは、ディレクトリ内のすべてのシンボリックリンクを再帰的に読み取り、find "$DIR" -type l それを1行ずつ処理します。

$line 名前を変更する必要があるシンボリックリンクです

CUR_LINK_PATH 古い道です

NEW_LINK_PATH 古いリンクパスで文字列置換を実行することによって取得されます。

古いシンボリックリンクが削除され、新しいシンボリックリンクが使用して作成されます ln -s "$NEW_LINK_PATH" "$line"


0

私は結局そのトリックをするように見えるコマンドラインのPHPスクリプトを書いてしまいました。

<?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";
            }
        }
    }
}
?>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.