web-dev-qa-db-fra.com

Pouvez-vous changer le point sur un lien symbolique après sa création?

Un système d'exploitation fournit-il un mécanisme (appel système - programme non en ligne de commande) permettant de changer le chemin d'accès référencé par un lien symbolique (lien symbolique), autrement qu'en dissociant l'ancien et en en créant un nouveau?

La norme POSIX ne le fait pas. Solaris 10 ne le fait pas. MacOS X 10.5 (Leopard) ne le fait pas. (Je suis à peu près certain que ni AIX ni HP-UX ne le font non plus. À en juger par cette liste de appels système Linux , Linux ne dispose pas non plus d'un tel appel système.)

Y at-il quelque chose qui fait?

(Je m'attends à ce que la réponse soit "Non".)


Comme il est difficile de prouver un négatif, réorganisons la question.

Si vous savez que certains systèmes d'exploitation (de type Unix) non déjà répertoriés ne disposent d'aucun appel système pour réécrire la valeur d'un lien symbolique (la chaîne renvoyée par readlink()) sans supprimer l'ancien lien symbolique et en créer un nouveau, ajoutez-le, ou les - dans une réponse.

110
Jonathan Leffler

Autant que je sache, non, vous ne pouvez pas. Vous devez l'enlever et le recréer. En réalité, vous pouvez écraser un lien symbolique et ainsi mettre à jour le chemin indiqué par celui-ci:

$ ln -s .bashrc test
$ ls -al test
lrwxrwxrwx 1 Pascal pascal 7 2009-09-23 17:12 test -> .bashrc
$ ln -s .profile test
ln: creating symbolic link `test': File exists
$ ln -s -f .profile test
$ ls -al test
lrwxrwxrwx 1 Pascal pascal 8 2009-09-23 17:12 test -> .profile

EDIT: comme l'OP l'a indiqué dans un commentaire, l'utilisation de l'option --force permet à ln d'effectuer un appel système à unlink() avant symlink(). Ci-dessous, le résultat de strace sur ma machine Linux le prouvant:

$ strace -o /tmp/output.txt ln -s -f .bash_aliases test
$ grep -C3 ^unlink /tmp/output.txt 
lstat64("test", {st_mode=S_IFLNK|0777, st_size=7, ...}) = 0
stat64(".bash_aliases", {st_mode=S_IFREG|0644, st_size=2043, ...}) = 0
symlink(".bash_aliases", "test")        = -1 EEXIST (File exists)
unlink("test")                          = 0
symlink(".bash_aliases", "test")        = 0
close(0)                                = 0
close(1)                                = 0

Donc, je suppose que la réponse finale est "non".

EDIT: Le texte suivant est copié de réponse d'Arto Bendiken sur unix.stackexchange.com, vers 2016.

Ce peut peut effectivement être effectué de manière atomique avec rename(2), en créant d'abord le nouveau lien symbolique sous un nom temporaire, puis en remplaçant proprement l'ancien lien symbolique en une fois. Comme le page de manuel déclare:

Si newpath fait référence à un lien symbolique, le lien sera écrasé.

Dans le shell, vous feriez ceci avec mv -T comme suit:

$ mkdir a b
$ ln -s a z
$ ln -s b z.new
$ mv -T z.new z

Vous pouvez strace cette dernière commande pour vous assurer qu'il utilise bien rename(2) sous le capot:

$ strace mv -T z.new z
lstat64("z.new", {st_mode=S_IFLNK|0777, st_size=1, ...}) = 0
lstat64("z", {st_mode=S_IFLNK|0777, st_size=1, ...}) = 0
rename("z.new", "z")                    = 0

Notez que dans ce qui précède, mv -T et strace sont spécifiques à Linux. 

Sous FreeBSD, utilisez mv -h alternativement.

Note de l'éditeur: C'est ainsi que Capistrano le fait depuis des années, depuis ~ 2.15. Voir cette demande d'extraction .

98
Pascal Thivent

Oui, vous pouvez!

$ ln -sfn source_file_or_directory_name softlink_name
151
Taai

Il n'est pas nécessaire de dissocier explicitement l'ancien lien symbolique. Tu peux le faire:

ln -s newtarget temp
mv temp mylink

(ou utilisez le lien symbolique équivalent et renommez les appels). Cela vaut mieux que de dissocier explicitement les liens car rename est atomique. Vous pouvez donc être sûr que le lien pointera toujours vers l'ancienne ou la nouvelle cible. Cependant, cela ne réutilisera pas l'inode d'origine.

Sur certains systèmes de fichiers, la cible du lien symbolique est stockée dans l'inode lui-même (à la place de la liste de blocage) si elle est suffisamment courte. ceci est déterminé au moment où il est créé.

En ce qui concerne l'affirmation que le propriétaire actuel et le groupe sont immatériels, symlink (7) sur Linux dit qu'il y a un cas où cela est significatif:

Le propriétaire et le groupe d'un lien symbolique existant peuvent être modifiés à l'aide de lchown (2). Le seul moment où la propriété d'un lien symbolique est importante est lorsque le lien est supprimé ou renommé dans un répertoire portant le sticky jeu de bits (voir stat (2)).

Les horodatages de dernier accès et de dernière modification d'un lien symbolique peuvent être changé avec utimensat (2) ou lutimes (3).

Sous Linux, les autorisations d'un lien symbolique ne sont utilisées dans aucune opération; les autorisations sont toujours 0777 (lecture, écriture et exécution pour toutes les catégories d'utilisateurs ) et ne peuvent pas être modifiées.

12
mark4o

Juste un avertissement aux bonnes réponses ci-dessus:

L'utilisation de la méthode -f/--force présente le risque de perdre le fichier si vous mélangez la source et la cible:

mbucher@server2:~/test$ ls -la
total 11448
drwxr-xr-x  2 mbucher www-data    4096 May 25 15:27 .
drwxr-xr-x 18 mbucher www-data    4096 May 25 15:13 ..
-rw-r--r--  1 mbucher www-data 4109466 May 25 15:26 data.tar.gz
-rw-r--r--  1 mbucher www-data 7582480 May 25 15:27 otherdata.tar.gz
lrwxrwxrwx  1 mbucher www-data      11 May 25 15:26 thesymlink -> data.tar.gz
mbucher@server2:~/test$ 
mbucher@server2:~/test$ ln -s -f thesymlink otherdata.tar.gz 
mbucher@server2:~/test$ 
mbucher@server2:~/test$ ls -la
total 4028
drwxr-xr-x  2 mbucher www-data    4096 May 25 15:28 .
drwxr-xr-x 18 mbucher www-data    4096 May 25 15:13 ..
-rw-r--r--  1 mbucher www-data 4109466 May 25 15:26 data.tar.gz
lrwxrwxrwx  1 mbucher www-data      10 May 25 15:28 otherdata.tar.gz -> thesymlink
lrwxrwxrwx  1 mbucher www-data      11 May 25 15:26 thesymlink -> data.tar.gz

Bien sûr, cela est prévu, mais des erreurs surviennent généralement. Donc, supprimer et reconstruire le lien symbolique est un peu plus de travail mais aussi un peu plus économe:

mbucher@server2:~/test$ rm thesymlink && ln -s thesymlink otherdata.tar.gz 
ln: creating symbolic link `otherdata.tar.gz': File exists

qui au moins garde mon dossier.

2
Markus Bucher

Ne pas le dissocier et créer le nouveau ne ferait-il pas la même chose au final?

1
matt b

Techniquement, il n'y a pas de commande intégrée pour éditer un lien symbolique existant. Cela peut être facilement réalisé avec quelques commandes courtes. 

Voici une petite fonction bash/zsh J'ai écrit pour mettre à jour un lien symbolique existant:

# -----------------------------------------
# Edit an existing symbolic link
#
# @1 = Name of symbolic link to edit
# @2 = Full destination path to update existing symlink with 
# -----------------------------------------
function edit-symlink () {
    if [ -z "$1" ]; then
        echo "Name of symbolic link you would like to edit:"
        read LINK
    else
        LINK="$1"
    fi
    LINKTMP="$LINK-tmp"
    if [ -z "$2" ]; then
        echo "Full destination path to update existing symlink with:"
        read DEST
    else
        DEST="$2"
    fi
    ln -s $DEST $LINKTMP
    rm $LINK
    mv $LINKTMP $LINK
    printf "Updated $LINK to point to new destination -> $DEST"
}
0
blizzrdof77

Juste au cas où cela aiderait: il existe un moyen de modifier un lien symbolique avec midnight commander (mc) . La commande de menu est (en français sur l'interface mc):

Fichier / Éditer le lien symbolique

qui peut être traduit en:

File / Edit symbolic link

Le raccourci est C-x C-s

Peut-être qu'il utilise en interne la commande ln --force, je ne sais pas.

Maintenant, j'essaie de trouver un moyen d'éditer tout un tas de liens symboliques à la fois (c'est comme ça que je suis arrivé ici).

0
Pierre