シンボリックリンクを通常のファイル(つまり、シンボリックリンクターゲットのコピー)に変換する最も直接的な方法は何ですか?
filename
がtarget
へのシンボリックリンクであるとします。コピーに変換するための明らかな手順は次のとおりです。
cp filename filename-backup
rm filename
mv filename-backup filename
より直接的な方法(つまり、単一のコマンド)がありますか?
シンボリックリンクを通常のファイルに変換する単一のコマンドはありません。最も直接的な方法は、readlink
を使用してシンボリックリンクが指すファイルを見つけ、そのファイルをシンボリックリンクにコピーすることです。
cp --remove-destination `readlink bar.pdf` bar.pdf
もちろん、bar.pdf
は、実際には、最初から通常のファイルであるため、ファイルが上書きされます。したがって、いくつかの健全性チェックが推奨されます。
他の回答の再ハッシュですが、渡されたリンクが実際にシンボリックリンクであることを確認するための「健全性チェック」を追加します。
removelink() {
[ -L "$1" ] && cp --remove-destination "$(readlink "$1")" "$1"
}
これは、ファイルがシンボリックリンクの場合、コピーコマンドを実行することを意味しています。
_for f in $(find -type l);do cp --remove-destination $(readlink $f) $f;done;
_
find -type l
_readlink $f
_cp --remove-destination $(readlink $f) $f
テキストファイルの場合、sed
コマンドでin-placeスイッチ(-i
)。これは、sed
がファイルを1回パスし、出力を一時ファイルに入れてから、元のファイルに合わせて名前を変更するためです。
変換なしでインラインsed
を実行するだけです:
sed -i ';' /path/to/symbolic/link
面白いシェルスクリプト、rsync
、または特別なGNUのcp
のオプション)は必要ありません。
_$ mv target link
_
ターゲットがわからない場合は、上記のtarget
を式$(readlink link)
に置き換えます。
_$ mv $(readlink link) link
_
mv
ユーティリティは、POSIXに似たシステムのrename
システムコールに対応します(少なくとも異なるファイルシステムボリュームで動作していない場合)。 rename
システムコールは、1回の操作で宛先オブジェクトが存在する場合、それを削除します。
ターゲットファイルをシンボリックリンクにmv
するだけです。
_$ touch target
$ ln -sf target link
$ ls -l target link
lrwxrwxrwx 1 kaz kaz 6 Sep 7 2016 link -> target
-rw-rw-r-- 1 kaz kaz 0 Sep 7 2016 target
$ mv target link
$ ls -l target link
ls: cannot access target: No such file or directory
-rw-rw-r-- 1 kaz kaz 0 Sep 7 2016 link
_
ボリューム全体でこれを行うと、シミュレートされます。 GNU Coreutils mv
は最初にrename
システムコールを試行します。失敗すると、unlink
を使用して宛先シンボリックリンクを削除し、コピーを実行します。
_$ touch /tmp/target
$ ln -sf /tmp/target link
$ ls -l /tmp/target link
lrwxrwxrwx 1 kaz kaz 11 Sep 7 2016 link -> /tmp/target
-rw-rw-r-- 1 kaz kaz 0 Sep 7 16:20 /tmp/target
$ strace mv /tmp/target link
[ ... snip ... ]
stat("link", {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
lstat("/tmp/target", {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
lstat("link", {st_mode=S_IFLNK|0777, st_size=11, ...}) = 0
rename("/tmp/target", "link") = -1 EXDEV (Invalid cross-device link)
unlink("link") = 0
open("/tmp/target", O_RDONLY|O_NOFOLLOW) = 3
fstat(3, {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
open("link", O_WRONLY|O_CREAT|O_EXCL, 0600) = 4
fstat(4, {st_mode=S_IFREG|0600, st_size=0, ...}) = 0
fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
read(3, "", 65536) = 0
[ ... ]
close(0) = 0
close(1) = 0
exit_group(0) = ?
+++ exited with 0 +++
$ ls -l /tmp/target link
ls: cannot access /tmp/target: No such file or directory
-rw-rw-r-- 1 kaz kaz 0 Sep 7 16:20 link
_
OSXで
rsync `readlink bar.pdf` bar.pdf
cp宛先ファイルを削除できます:
cp --remove-destination target filename
多くの人がすでに次の解決策を述べています。
cp --remove-destination `readlink file` file
ただし、これはシンボリックリンクされたディレクトリでは機能しません。
recursiveおよびforceを追加しても機能しません。
cp -rf --remove-destination `readlink file` file
cp:ディレクトリ「path/file」を自身にコピーすることはできません」「file」
したがって、最初にシンボリックリンクを完全に削除する方がおそらく安全です。
resolve-symbolic-link() {
if [ -L $1 ]; then
temp="$(readlink "$1")";
rm -rf "$1";
cp -rf "$temp" "$1";
fi
}
あなたが望んでいたような正確なワンライナーではありませんが、これをシェル環境に入れてください。
これを頻繁に行う場合は、kbrockの回答をシェルスクリプトに適合させ、/ usr/bin /に配置することもできます。以下の線に沿ったもの:
if [ $# -ne 1 ]
then
echo "Usage: $0 filename"
exit 1
fi
[ -L "$1" ] && cp --remove-destination "$(readlink "$1")" "$1"
それをchmod + xして、通常のコマンドとして実行します。
このソリューションは、symlinkファイルおよびsymlinkフォルダー/サブフォルダーで機能します。
1行、スクリプトは不要です。これは、他の場所にシンボリックリンクをエクスポートまたは転送するのに理想的です。
すべてをフォルダーに入れます。
rsync --archive --copy-links --recursive folderContainingSymlinkFilesAndSymlinkFoldersAndSubfolders myNewFolder
「相対」シンボリックリンクの場合、@ jaredの回答にawkステートメントを追加できます。
for f in $(find . -type l); do /bin/cp -rf --remove-destination -f $(find . \! -type l -name $(readlink $f | awk -F"../" '{print $NF}')) $f;done;
ディレクトリを指すシンボリックリンクがある場合は、cp --remove-destinationはシンボリックリンクディレクトリと一緒に正しく機能しないため、より根本的なアプローチを使用する必要があります。
for f in `find . -type l`; do (cd `dirname $f`; target=`basename $f`; source=`readlink $target` ; rm -rf $target && cp -r $source $target); done
確かに、これはより少ないオーバーヘッドで記述できます。しかし、私の意見を読むのはとても良いことです。
単一のコマンドはありません。ただし、コピーが不要で、別の参照だけが必要な場合は、シンボリックリンクをリンク(「ハードリンク」とも呼ばれる)に置き換えることができます。これは、同じパーティション(BTW)上にある場合にのみ機能します。
rm filename
ln target filename
これは私にとって完璧に機能しました(スペースで動作するように編集された):
find . -type l | while read f; do /bin/cp -rf --remove-destination -f $(find . -name $(readlink "${f}")) "${f}";done;
現在の作業フォルダーにあるすべてのシンボリックリンクを通常のファイルに再帰的に変換できます。また、上書きするように要求しません。 「/ bin/cp」が存在するため、OSで「-rf」が機能しなくなる可能性のあるcp -iエイリアスをバイパスできます。
Rsyncは、-Lフラグを使用して、シンボリックリンクを簡単に区別できます。
[user@workstation ~]$ rsync -h | grep -- -L
-L, --copy-links transform symlink into referent file/dir
それは次のように簡単です:rsync -L <symlink> <destination>