Comment convertir un lien symbolique en fichier régulier?

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

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

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

Est-il un moyen plus direct (c'est à dire une seule commande)?

42
demandé sur nibot 2011-12-04 21:51:59

14 réponses

Il n'y a pas de commande unique pour convertir un lien symbolique en un fichier régulier. Le moyen le plus direct est d'utiliser readlink pour trouver le fichier vers lequel pointe un lien symbolique, puis de 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 pour commencer, ensuite ce sera supprimé le fichier. Certaines vérifications serait donc souhaitable.

43
répondu nibot 2012-11-15 11:06:10

Juste un ressaisissement des réponses des autres, mais en ajoutant le "contrôle de santé mentale" pour s'assurer que le lien passé est en fait un lien symbolique:

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

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

17
répondu kbrock 2015-03-24 14:54:58
for f in $(find -type l);do cp --remove-destination $(readlink $f) $f;done;
  • Vérifiez les liens symboliques dans le répertoire courant et les sous-répertoires find -type l
  • récupère le chemin du fichier lié readlink $f
  • Supprimer lien symbolique et copier le fichier cp --remove-destination $(readlink $f) $f
14
répondu Yadhu 2016-04-12 18:04:40

Pour les fichiers texte, la commande sed peut le faire en une seule ligne si vous lui passez le commutateurin-place (-i). C'est parce que sed fait un seul passage sur un fichier, chats la sortie dans un fichier temporaire qu'il renomme par la suite pour correspondre à l'original.

Il suffit de faire un inline sed sans transformations:

sed -i ';' /path/to/symbolic/link
8
répondu dsclose 2016-05-12 18:59:13

Sur OSX

Rsync ' readlink bar.pdf bar.pdf

7
répondu Paul Beusterien 2013-01-30 18:44:39

Il N'y a pas besoin de scripts shell drôles, rsync, ou D'options GNU spéciales 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 les systèmes de type POSIX (au moins lorsqu'ils ne fonctionnent pas sur différents volumes de systèmes 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 à travers les volumes, il est simulé. Le GNU coreutils mv tente 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
répondu Kaz 2016-09-07 23:34:18

cp pouvez supprimer le fichier de destination:

cp --remove-destination target filename
4
répondu Andriy Radyk 2011-12-05 00:02:09

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

cp --remove-destination `readlink file` file

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

Ajout d'un récursive et force ne fonctionne pas, soit:

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

Cp: impossible de copier un répertoire, ‘chemin/fichier, en 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'aviez espéré, mais mettez ceci dans votre coquille de l'environnement, et il peut être.

2
répondu Trevor Hickey 2015-05-18 05:36:51

Cela a parfaitement fonctionné 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;

Vous permet de convertir récursivement tous les liens symboliques du dossier de travail en cours vers son fichier normal. Aussi ne vous demande pas de les remplacer. le "/ bin / cp "existe de sorte que vous pouvez contourner un alias cp-i possible sur votre système d'exploitation qui empêche le" - rf " de fonctionner.

1
répondu Jared 2016-06-27 19:49:27

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 (alias "lien dur"). Cela ne fonctionne que s'ils sont sur la même partition, BTW.

rm filename
ln target filename
0
répondu Brian Cain 2011-12-04 17:59:59

Rsync peut nativly déférence le lien symbolique pour vous en utilisant -l drapeau.

[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
répondu user3879068 2014-07-26 05:12:56

En 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 il est assez bon de lire à mon avis.

0
répondu ttwhy 2016-03-10 16:45:30

Cette solution fonctionne avec les fichiers de liens symboliques et les dossiers/sous-dossiers de liens symboliques.

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 --copie-liens --recursive folderContainingSymlinkFilesAndSymlinkfoldersandsubfolders monnouveaudossier

0
répondu Jean-Sebastien Perron 2016-06-09 15:40:13

Une autre approche si vous le faites souvent est d'adapter la réponse de kbrock dans un script shell et de la mettre dans / usr / bin/. Quelque chose dans le sens de:

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

Chmod + x, puis exécutez-le simplement comme une commande normale.

0
répondu BANZ1111 2016-09-07 23:20:37