web-dev-qa-db-ja.com

シンボリックリンクを通常のファイルに変換する方法は?

シンボリックリンクを通常のファイル(つまり、シンボリックリンクターゲットのコピー)に変換する最も直接的な方法は何ですか?

filenametargetへのシンボリックリンクであるとします。コピーに変換するための明らかな手順は次のとおりです。

cp filename filename-backup
rm filename
mv filename-backup filename

より直接的な方法(つまり、単一のコマンド)がありますか?

49
nibot

シンボリックリンクを通常のファイルに変換する単一のコマンドはありません。最も直接的な方法は、readlinkを使用してシンボリックリンクが指すファイルを見つけ、そのファイルをシンボリックリンクにコピーすることです。

cp --remove-destination `readlink bar.pdf` bar.pdf

もちろん、bar.pdfは、実際には、最初から通常のファイルであるため、ファイルが上書きされます。したがって、いくつかの健全性チェックが推奨されます。

48
nibot

他の回答の再ハッシュですが、渡されたリンクが実際にシンボリックリンクであることを確認するための「健全性チェック」を追加します。

removelink() {
  [ -L "$1" ] && cp --remove-destination "$(readlink "$1")" "$1"
}

これは、ファイルがシンボリックリンクの場合、コピーコマンドを実行することを意味しています。

21
kbrock
_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
18
Yadhu

テキストファイルの場合、sedコマンドでin-placeスイッチ(-i)。これは、sedがファイルを1回パスし、出力を一時ファイルに入れてから、元のファイルに合わせて名前を変更するためです。

変換なしでインラインsedを実行するだけです:

sed -i ';' /path/to/symbolic/link
9
dsclose

面白いシェルスクリプト、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
_
9
Kaz

OSXで

rsync `readlink bar.pdf` bar.pdf

7
Paul Beusterien

cp宛先ファイルを削除できます:

cp --remove-destination target filename
4
Andrii Radyk

多くの人がすでに次の解決策を述べています。

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
}

あなたが望んでいたような正確なワンライナーではありませんが、これをシェル環境に入れてください。

2
Trevor Hickey

これを頻繁に行う場合は、kbrockの回答をシェルスクリプトに適合させ、/ usr/bin /に配置することもできます。以下の線に沿ったもの:

if [ $# -ne 1 ] 
then
  echo "Usage: $0 filename"
  exit 1
fi
[ -L "$1" ] && cp --remove-destination "$(readlink "$1")" "$1"

それをchmod + xして、通常のコマンドとして実行します。

1
BANZ1111

このソリューションは、symlinkファイルおよびsymlinkフォルダー/サブフォルダーで機能します。

1行、スクリプトは不要です。これは、他の場所にシンボリックリンクをエクスポートまたは転送するのに理想的です。

すべてをフォルダーに入れます。

rsync --archive --copy-links --recursive folderContainingSymlinkFilesAndSymlinkFoldersAndSubfolders myNewFolder

1
user6411287

「相対」シンボリックリンクの場合、@ 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

確かに、これはより少ないオーバーヘッドで記述できます。しかし、私の意見を読むのはとても良いことです。

0
ttwhy

単一のコマンドはありません。ただし、コピーが不要で、別の参照だけが必要な場合は、シンボリックリンクをリンク(「ハードリンク」とも呼ばれる)に置き換えることができます。これは、同じパーティション(BTW)上にある場合にのみ機能します。

rm filename
ln target filename
0
Brian Cain

これは私にとって完璧に機能しました(スペースで動作するように編集された):

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エイリアスをバイパスできます。

0
Jared

Rsyncは、-Lフラグを使用して、シンボリックリンクを簡単に区別できます。

[user@workstation ~]$ rsync -h | grep -- -L
 -L, --copy-links            transform symlink into referent file/dir

それは次のように簡単です:rsync -L <symlink> <destination>

0
user3879068