web-dev-qa-db-fra.com

Comment convertir un lien symbolique en fichier normal?

Quel est le moyen le plus direct de convertir un lien symbolique en un fichier normal (c'est-à-dire une copie de la cible du lien symbolique)?

Supposons que filename soit un lien symbolique vers target. La procédure évidente pour le transformer en copie est la suivante:

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

Existe-t-il un moyen plus direct (une seule commande)?

44
nibot

Il n'y a pas de commande unique pour convertir un lien symbolique en un fichier normal. Le moyen le plus direct consiste à utiliser readlink pour rechercher le fichier pointé par un lien symbolique, puis à copier ce fichier sur le lien symbolique:

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

Bien sûr, si bar.pdf est, en fait, un fichier normal pour commencer, cela écrasera le fichier. Une vérification de la santé mentale serait donc souhaitable.

46
nibot

Juste une répétition des réponses des autres, mais en ajoutant le "contrôle d'intégrité" pour s'assurer que le lien transmis est en fait un lien symbolique

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

Cela signifie que si le fichier est un lien symbolique, exécutez la commande copy.

19
kbrock
for f in $(find -type l);do cp --remove-destination $(readlink $f) $f;done;
  • Vérifier les liens symboliques dans le répertoire actuel et les sous-répertoires find -type l
  • Obtenir le chemin du fichier lié readlink $f
  • Supprimer le lien symbolique et copier le fichier cp --remove-destination $(readlink $f) $f
16
Yadhu

Pour les fichiers texte, la commande sed peut le faire en une seule ligne si vous lui passez le in-place switch (-i). En effet, sed effectue un seul passage sur un fichier, convertit la sortie en un fichier temporaire qu’elle renomme par la suite pour correspondre à l’original.

Il suffit de faire une sed en ligne sans transformation:

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

Sur OSX 

rsync `readlink bar.pdf` bar.pdf

7
Paul Beusterien

Il n’est pas nécessaire d’utiliser des scripts Shell amusants, rsync ou des options spéciales GNU sur cp. Tout simplement:

$ mv target link

Si nous ne connaissons pas la cible, nous substituons l'expression $(readlink link) à target ci-dessus:

$ mv $(readlink link) link

L'utilitaire mv correspond à l'appel système rename sur des systèmes de type POSIX (du moins lorsqu'il ne fonctionne pas sur différents volumes de système de fichiers). L'appel système rename supprime l'objet de destination, s'il existe, en une seule opération.

Nous pouvons simplement mv le fichier cible vers le lien symbolique:

$ 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

Si nous faisons cela sur plusieurs volumes, cela est simulé. Le GNU Coreutils mv essaie d’abord l’appel système rename. Lorsque cela échoue, il utilise unlink pour supprimer le lien symbolique de destination et effectue une copie:

$ 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
7
Kaz

cppeut supprimer le fichier de destination:

cp --remove-destination target filename
4
Andrii Radyk

Beaucoup ont déjà indiqué la solution suivante: 

cp --remove-destination `readlink file` file

Cependant, cela ne fonctionnera pas sur les répertoires liés symboliquement. 

Ajouter une récursive et force ne fonctionnera pas non plus: 

cp -rf --remove-destination `readlink file` file

cp: impossible de copier un répertoire "chemin/fichier" dans lui-même, "fichier"  

Par conséquent, il est probablement plus sûr de supprimer entièrement le lien symbolique en premier: 

resolve-symbolic-link() {
  if [ -L $1 ]; then
      temp="$(readlink "$1")";
      rm -rf "$1";
      cp -rf "$temp" "$1";
  fi
}

Pas exactement un one-liner comme vous l’espériez, mais mettez-le dans votre environnement Shell, et c’est possible.

2
Trevor Hickey

Cela a fonctionné parfaitement pour moi ( édité pour travailler avec des espaces ):

find . -type l | while read f; do /bin/cp -rf --remove-destination -f $(find . -name $(readlink "${f}")) "${f}";done;

Permet de convertir de manière récursive tous les liens symboliques du dossier de travail en cours vers son fichier normal. Aussi ne vous demande pas d'écraser. le "/ bin/cp" existe afin que vous puissiez ignorer un possible alias cp -i sur votre système d'exploitation qui empêche le "-rf" de fonctionner.

1
Jared

Cette solution fonctionne avec les fichiers symlink et les dossiers/sous-dossiers symlink.

Une ligne, aucun script nécessaire . Ce serait idéal pour exporter ou transférer des liens symboliques ailleurs.

Mettez tout dans un dossier.

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

1

dans le cas de liens symboliques "relatifs", vous pouvez ajouter une instruction awk à la réponse @jared:

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;

Si vous avez des liens symboliques pointant vers des répertoires, vous devez utiliser une approche plus radicale car cp --remove-destination ne fonctionne pas correctement avec les répertoires de liens symboliques

for f in `find . -type l`; do (cd `dirname $f`; target=`basename $f`; source=`readlink $target` ; rm -rf $target && cp -r $source $target); done

Bien sûr, cela pourrait être écrit avec moins de frais généraux. mais c'est assez bon à lire à mon avis.

0
ttwhy

Il n'y a pas de commande unique. Mais si vous ne voulez pas de copie et que tout ce que vous voulez est une autre référence, vous pouvez remplacer le lien symbolique par un lien (aka "lien dur"). Cela ne fonctionne que s’ils se trouvent sur la même partition, BTW.

rm filename
ln target filename
0
Brian Cain

Rsync peut naturellement déférencer le lien symbolique pour vous en utilisant l'option -L.

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

Ce serait aussi simple que: rsync -L <symlink> <destination>

0
user3879068

Une autre approche consiste souvent à adapter la réponse de kbrock à un script shell et à l'insérer dans/usr/bin /. Quelque chose dans le genre de:

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

chmod + x it, puis exécutez-le simplement en tant que commande normale.

0
BANZ1111