シンボリックリンクをファイルで置き換える


31

すべてのシンボリックリンクをリンク先のファイルで簡単に置き換える方法はありますか?


3
どのような問題を解決しようとしていますか?
ダニエルベック

3
別のドライブへのシンボリックリンクがたくさんあります。他の場所で参照されているすべてのファイルをそのドライブから移動して、削除できるようにする必要があります。
マーティトレンノス

回答:


14

「簡単」のいくつかの定義:

#!/bin/sh
set -e
for link; do
    test -h "$link" || continue

    dir=$(dirname "$link")
    reltarget=$(readlink "$link")
    case $reltarget in
        /*) abstarget=$reltarget;;
        *)  abstarget=$dir/$reltarget;;
    esac

    rm -fv "$link"
    cp -afv "$abstarget" "$link" || {
        # on failure, restore the symlink
        rm -rfv "$link"
        ln -sfv "$reltarget" "$link"
    }
done

リンク名を引数としてこのスクリプトを実行します。たとえば find . -type l -exec /path/tos/script {} +


2
編集、anonに感謝しますが、スクリプト、必要なすべての場所で変数を引用することにより、スペースを含むファイル名をうまく処理します。変更する"$var"には、"${var}"SH / bashでNOOPです。1つのbashism([[)を削除しました。残りはPOSIX shと互換性があります。
粗さ

シンボリックリンク障害を処理するためのさらに堅牢な方法cpは、同じディレクトリ内の一時ファイルを使用してから、mv -fその一時ファイルを元の状態にすることです。これCtrl-Cによりrmcpコマンドを押し続けたり、コマンドとコマンドの間でファイルシステムがいっぱいになるなどの問題を防ぐことができます(したがって、新しいlnものでも動作しなくなります)。一時ファイル名はls -a、必要に応じて後でクリーンアップするために簡単に見つけることができます。
氏Fooz

サイドノートとして、私はケースブロックのabstarget=$(readlink -f "$link")代わりに単に使用しなかった理由を真剣に思い出すことができませんが、それは移植性の理由だったかもしれません。
-grawity

17

tarを使用してデータを新しいディレクトリにコピーする方が簡単な場合があります。

-H      (c and r mode only) Symbolic links named on the command line will
        be followed; the target of the link will be archived, not the
        link itself.

このようなものを使用できます

tar -hcf - sourcedir | tar -xf - -C newdir

tar --help:
-H, --format=FORMAT        create archive of the given format
-h, --dereference          follow symlinks; archive and dump the files they point to

1
私はあなたの解決策が大好きですが、あなたのメッセージの最後の部分を理解していません。私はあなたがする必要があります:tar -hcf - sourcedir | tar -xf - -C newdir
セブダロチャ

1
同意して、この回答はコメントごとに更新する必要があります。
アスタバダ14年

1
cp -Lより簡単なソリューションです
-plesiv

@plesiv true、およびposix準拠ですが、すべてのcp実装がディレクトリをコピーするわけではありません。
Wyatt8740

16

私が正しく理解していれば-Lcpコマンドのフラグはあなたが望むものを正確に実行するはずです。

すべてのシンボリックリンクをコピーするだけで、それらが指すファイルに置き換えられます。


4
おかげで-ほとんど私が必要なもの:私のような何かしなければならなかったcp -L files tmp/ && rm files && cp tmp/files . ...あなたは明確にした場合、あなたはおそらくより多くの人々を助けるだろうが
セージ

5

「簡単」はおそらくあなたの機能です。

「find」コマンドラインユーティリティを使用してシンボリックにリンクされたファイルを検索し、rmとcpを呼び出してファイルを削除および置換するスクリプトをおそらく作成します。symリンクを移動する前に、十分な空き領域が残っていることをfindチェックで呼び出すアクションを実行することもできます。

別の解決策は、symリンクなどのsymリンクを隠す何かを通して問題のファイルシステムをマウントし、そこからすべてをコピーすることです。しかし、多くの場合、そのようなことは他の問題を引き起こすでしょう。

あなたの質問に対するより直接的な答えはおそらく「はい」でしょう。

編集:より具体的な情報のリクエストに応じて。findmanページによると、このコマンドは/からの2つのディレクトリの深さまでのすべてのsymリンクファイルをリストします。

find / -maxdepth 2 -type l -print

これはここで見つかりました

findを見つけて何かを実行させるには:

find / -maxdepth 2 -type l -exec ./ReplaceSymLink.sh {} \;

作成したばかりのスクリプトを呼び出し、見つけたファイル名を渡すと思います。または、find出力をファイルにキャプチャし(「find [blah]> symlinks.data」などを使用)、そのファイルを元のコピーを適切に処理するために記述したスクリプトに渡すこともできます。


?少し一般的です-あなたは詳しく説明できますか?
リンカー3000

2
構文は次のとおりです-exec ./ReplaceSymLink.sh {} \;
-grawity

これはアイテムを見つけに行くもので、答えとしてマークされたものはリンクを置き換えるために使用されます!
マーティトレンノス

3

これは私が使用したonelinerです。すべてのローカルファイルが「ソース」内の別のファイルへのリンクであると仮定します。パターンまたは「検索」でファイル選択を絞り込むことができます。ご使用前にご理解ください。

for in *; do cp --remove-destination source / $ f $ f; やった

お役に立てれば


readlinkの使用方法:for f in *; do cp ---- remove-destination "$(readlink $ f)" "$ f"; 完了
ディエゴ

はい、それは良い考えですが、操作の一部を制御できなくなります。私のソリューションの1つの制限は、真ん中に空白があるファイルや、非常に長いリストでは機能しないことです。おそらく最終的な解決策は、上記の「find --exec」と「remove destination」を組み合わせることです。誰か試してみたい?
MastroGeppetto

中央の空白は、 "$ f"を二重引用符で囲むことにより軽減する必要があります。「forループ」の代わりに「find&xargs」で使用する方法を以下に示します。find ./ -type l -print0 | xargs -0 -n1 -i sh -c 'cp --remove-destination $(readlink "{ } ")" {} "'可視性の別の回答として投稿しました。superuser.com/a/1329543/499386
ディエゴ

2
find . -type l -exec cp --dereference --recursive '{}' '{}'.dereferenced \;

の各シンボリックリンクされたファイル/フォルダーのコピーを作成します<filename>.dereferenced。これは、それらを直接置き換えるよりも安全です(便利でない場合)。コピーしたデータをシンボリックリンクのファイル名に移動することは、読者の演習として残しておきます。


2

前のアイデアのいくつかを使用して、次のコマンドはすべてのシンボリックリンクを元のシンボリックリンクに再帰的に置き換えます。

find . -type l -exec bash -c "echo 'Replacing {} ...';  cp -LR '{}' '{}'.dereferenced;  rm '{}';  mv '{}'.dereferenced '{}'" \;


1

たくさんの良い答えがありますが、私はあなたが簡単なものを探していたので

for i in *; do link=$(readlink $i) && rm $i && mv $link $i; done

少し拡張すると、シンボリックリンクを見つけるのに役立ちます。-type l`; do src = $(readlink $ lnk)&& rm $ lnk && mv $ src $ lnk; 完了(階層でのテストは行われませんが、バックティックには注意してください)
ローマンスーシ

1

通常、リンクをたどってファイルをコピーすると予想されるときに、リンクをコピーするgwenviewで同じ問題が発生しました。

すべてのリンクをたどり、指示されたすべてのファイルをディレクトリにコピーすることでディレクトリを「クリーン」にするために、スクラッチディレクトリを作成しました。たとえば、

"for file in `ls`; do cp -L $file scratchdir/$file; done; mv scratchdir/* ./" 

これはチェックが行われないためスクリプトに入れるには危険すぎますが、私の問題は解決しました。



0

私のウェブホテルではbashスクリプトが許可されていなかったため、私は1行のバージョンを作成しました。

before:
> find . -type l | wc -l
358

> for link in `find . -type l` ; do echo "$link : "; ls -al $link ; cp $link notalink; unlink $link; mv notalink $link ; ls -al $link; done
...

after:
> find . -type l | wc -l
0
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.