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)?
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.
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.
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
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
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
cp pouvez supprimer le fichier de destination:
cp --remove-destination target filename
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.
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.
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
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>
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.
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
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.