web-dev-qa-db-ja.com

すべてのシンボリックリンクを元のシンボリックリンクに置き換えます

私は次のディレクトリ構造を持っています

/symdir
  sym1 -> ../dir1
  sym2 -> ../dir2
  hello.txt

その後

/dir1
  some
  files
  here
/dir2
  more
  files

Symdir(sym1、sym2)のシンボリックリンクをオリジナルに置き換えたいと思います。つまり.

some_awesome_bash_func symdir symdir_output

作成します

/symdir_output
  /dir1
    some
    files
    here
  /dir2
    more
    files
  hello.txt

どうすればこれを達成できますか?

29
Ken Hirakawa

おそらく最善の方法ではありませんが、機能します。

#!/usr/bin/bash

for link in $(find /symdir -type l)
do
  loc="$(dirname "$link")"
  dir="$(readlink "$link")"
  mv "$dir" "$loc"
  rm "$link"
done
10
Daniel Haley

私の非常に個人的なトリック:

sed -i '' **/*

Bashglobstarオプションを使用する**を使用していることに注意してください。事前に有効にする必要がある場合があります:

shopt -s globstar
64
Julien Palard

これはrsyncで簡単に行うことができます:

rsync symdir/ symdir_output/ -a --copy-links -v

(-aは基本的にファイルに関するすべての詳細を保持することを意味し、-copy-linksは-aをオーバーライドしてシンボリックリンクを実際のファイル/ディレクトリに変換します。-vは詳細を表します)

編集:

申し訳ありませんが、私の解決策はあなたが求めていたものを正確に実行しません。宛先名を使用する代わりに、シンボリックリンクの名前を保持します。 symdir_outputには、dir1とdir2の代わりにsym1とsym2が含まれます(ただし、sym1とsym2はdir1とdir2の実際のコピーになります)。それがまだあなたのために働くことを願っています。

24
Jonathan Amend

関連する答えとして、このソリューションはファイルを元の場所に保持し、シンボリックリンクの代わりにコピーを作成します

#/bin/bash

for f in $(find . -maxdepth 1 -type l)
do
    cp --remove-destination $(readlink -e $f) $f
done
12
PinkFloyd

tl; dr:はるかに一般的で、はるかに信頼できる答え:

find -type l -exec sh -c 'PREV=$(realpath -- "$1") && rm -- "$1" && cp -ar -- "$PREV" "$1"' resolver {} \;

「rsync-to-other-destination」アプローチは厳密に優れており、通常はより良い設計につながります。

@PinkFloydによる回答は、通常とは異なるファイル名、「埋め込まれた」シンボリックリンク、またはシンボリックリンクされたディレクトリではうまく機能しません。ディレクトリシンボリックリンクを解決したかったのでここに来たので、他の人もこの理由でこの質問を見つけることを期待しています。また、私のバージョンのcp(GNU coreutils 8.25)は、ディレクトリを操作するための@PinkFloydの回答に対して--remove-destinationを適切に処理しません。したがって、この回答では手動のrmを使用します。

また注意してください:

  • -rfがない。これは、シンボリックリンクがディレクトリではなく、-rを必要としないためです。また、アクセス許可が制限されたシンボリックリンクがない限り(なぜそれが必要なのですか?!)、-fも必要ありません。
  • realpathは、現在のシステム、現在のコンテキストでの実際の場所を見つけることができ、他に何も問題がないため、このコンテキストでは完全に問題ありません。このパスはディスクに書き込まれないため、これはエラーではありません。
  • resolver文字列はsh用です。 man shを参照してください。
  • シンボリックリンクが--versionなどと呼ばれる場合は、どこでも二重ダッシュが必要です。
  • findの事前注文保証(「親ディレクトリはそのコンテンツの前のどこかにリストされています」)により、これは最初に親ディレクトリを置き換え、次にシンボリックリンクされたディレクトリ内のシンボリックリンクを置き換えます。したがって、「スタックされた」シンボリックリンクで完全に正常に機能します。
6
Mike Gebirge

私はそれをこのようにしました:

_ls -la | awk '/-\>/{system("rm "$10); system("cp "$12" .")}'
_

使い方:

_ls -la_は次のようなものを出力します:

_lrwxr-xr-x  1 username  groupname   44 10 Oct 12:17 Queue.Swift -> ../../../Platform/DataStructures/Queue.Swift
_

列10は、ローカルファイルの名前である_Queue.Swift_です。
列12は_../../../Platform/DataStructures/Queue.Swift_で、これはリンクターゲットの名前です。

awkコマンドの最初の部分は_'/-\>/'_です。これは、「正規表現を使用して_->_を含む行を一致させる」ことを意味します。

Awkコマンドの次の部分は、systemへの2回の呼び出しです。

最初のsystem("rm "$10)system("rm Queue.Swift")に展開されます。
これにより、元のファイル(シンボリックリンク)が削除されます

2番目はsystem("cp "$12" .")です。これはsystem("cp ../../../Platform/DataStructures/Queue.Swift .")に展開されます。

すべてをまとめると、各ファイル(シンボリックリンク)に対して何が起こるかというと、最初にシンボリックリンクを削除し、次にターゲットファイルをその場所にコピーします。


元の質問の一部ではありませんが、私はこれをgitと組み合わせて使用​​していました。たまたまそうしている場合は、後で_git status ._を実行すると、次のような一連のタイプの変更が表示されます(他には何も表示されません)。

_typechange: Queue.Swift
_
1
Orion Edwards

これは、@ DanielHaleyに基づくもう少し一般的なソリューションです。

また、参照用にシンボリックリンクを保持し、編集するディレクトリを選択するようにユーザーに求めます。

ls
read -p 'Which directory do you want to update?: ' linkdir

pushd $linkdir

for linkname in $(find ./ -type l)
do
  orig=$(readlink $linkname)
  mv $linkname ${linkname}.linkbak
  cp $orig $linkname
done

popd
0
FGiorlando