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)?
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.
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.
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
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
Sur OSX
rsync `readlink bar.pdf` bar.pdf
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
cppeut supprimer le fichier de destination:
cp --remove-destination target filename
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.
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.
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
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.
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
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>
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.