76 votes

Comment convertir un lien symbolique en fichier ordinaire ?

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

Supposons que filename est 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 (c'est-à-dire une seule commande) ?

70voto

nibot Points 5057

Il n'existe pas de commande unique pour convertir un lien symbolique en fichier ordinaire. Le moyen le plus direct est d'utiliser readlink pour trouver le fichier vers lequel pointe 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 régulier pour commencer, alors cela va bloquer le fichier. Il est donc conseillé de procéder à une vérification de l'intégrité du fichier.

39voto

Yadhu Points 261
for f in $(find -type l);do cp --remove-destination $(readlink $f) $f;done;
  • Vérifier les liens symboliques dans le répertoire courant 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

22voto

kbrock Points 328

Je ne fais que reprendre les réponses des autres, mais ajoutez le "contrôle d'intégrité" pour vous assurer que le lien transmis est bien un lien symbolique :

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

Cela signifie que si le fichier est un lien symbolique, il faut exécuter la commande de copie.

19voto

dsclose Points 320

Pour les fichiers texte, l'option sed peut faire cela en une seule ligne si vous lui passez la commande en place interrupteur ( -i ). Cela s'explique par le fait que sed effectue un seul passage sur un fichier, et enregistre la sortie dans un fichier temporaire qu'il renomme ensuite pour correspondre à l'original.

Il suffit de faire un inline sed sans transformation :

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

10voto

Kaz Points 18072

Il n'est pas nécessaire d'avoir recours à des scripts shell amusants, rsync ou les options spéciales de GNU sur cp . Tout simplement :

$ mv target link

Si on ne connaît pas la cible, on substitue l'expression $(readlink link) pour target ci-dessus :

$ mv $(readlink link) link

El mv l'utilité correspond à la rename sur les systèmes POSIX-like (du moins lorsqu'ils ne fonctionnent pas sur des volumes de systèmes de fichiers différents). L'adresse 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 on fait cela sur plusieurs volumes, c'est simulé. Les GNU Coreutils mv essaie d'abord le rename l'appel système. Si 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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X