私は次のディレクトリ構造を持っています
/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
どうすればこれを達成できますか?
おそらく最善の方法ではありませんが、機能します。
#!/usr/bin/bash
for link in $(find /symdir -type l)
do
loc="$(dirname "$link")"
dir="$(readlink "$link")"
mv "$dir" "$loc"
rm "$link"
done
私の非常に個人的なトリック:
sed -i '' **/*
Bashglobstarオプションを使用する**
を使用していることに注意してください。事前に有効にする必要がある場合があります:
shopt -s globstar
これはrsyncで簡単に行うことができます:
rsync symdir/ symdir_output/ -a --copy-links -v
(-aは基本的にファイルに関するすべての詳細を保持することを意味し、-copy-linksは-aをオーバーライドしてシンボリックリンクを実際のファイル/ディレクトリに変換します。-vは詳細を表します)
編集:
申し訳ありませんが、私の解決策はあなたが求めていたものを正確に実行しません。宛先名を使用する代わりに、シンボリックリンクの名前を保持します。 symdir_outputには、dir1とdir2の代わりにsym1とsym2が含まれます(ただし、sym1とsym2はdir1とdir2の実際のコピーになります)。それがまだあなたのために働くことを願っています。
関連する答えとして、このソリューションはファイルを元の場所に保持し、シンボリックリンクの代わりにコピーを作成します
#/bin/bash
for f in $(find . -maxdepth 1 -type l)
do
cp --remove-destination $(readlink -e $f) $f
done
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
の事前注文保証(「親ディレクトリはそのコンテンツの前のどこかにリストされています」)により、これは最初に親ディレクトリを置き換え、次にシンボリックリンクされたディレクトリ内のシンボリックリンクを置き換えます。したがって、「スタックされた」シンボリックリンクで完全に正常に機能します。私はそれをこのようにしました:
_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
_
これは、@ 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