Come posso modificare i collegamenti simbolici?


64

La mia comprensione di base di un collegamento simbolico è come un file speciale, un file che contiene un percorso di stringa a un altro file. Il VFS del kernel ne estrae molto, ma c'è qualche ragione per cui i collegamenti simbolici sembrano impossibili da modificare?

In altre parole: posso modificare un link simbolico? In caso contrario, perché no?


Capisco che ci sono vari modi per sostituire i collegamenti simbolici (due alternative sono attualmente nella sezione delle risposte), ma sarebbe interessante avere una spiegazione sul perché la sostituzione sembra essere l'unico modo per gestire i collegamenti simbolici. Perché non puoi semplicemente cambiare dove indicano?


La tua comprensione è un po 'limitata; l'unica ragione per cui si chiama "file" è perché non esiste una parola migliore per farlo.
Shadur,

5
A differenza della atrocità imbarazzante che è la variante di windows, i collegamenti simbolici in stile posix operano sul / nel livello del filesystem stesso. L'unico modo per modificarne uno sarebbe modificare direttamente il filesystem - e generalmente non ne vale la pena.
Shadur,

I file @Shadur .lnk non sono in realtà collegamenti simbolici per iniziare (e NTFS ha avuto collegamenti simbolici adeguati da Vista); sono più simili a scorciatoie per l'esecuzione di comandi, sia che si stia cambiando in una cartella specifica o avviando un programma con argomenti specifici e con un certo CWD.
JAB,

Risposte:


36

Dato che -ffa solo una sostituzione silenziosa, puoi fare una sostituzione atomica con mv -T(-T lo fa funzionare anche se /loc.../link è una directory) :

ln -s /location/to/link linkname
# ... 
ln -s /location/to/link2 newlink
mv -T newlink linkname

linkname è accessibile durante tutto il processo.


7
Questo ti dà la sostituzione atomica, anche se stai ancora effettuando una sostituzione anziché una modifica (il nuovo collegamento ha un nuovo numero di inode).
psusi,

2
@psusi Sono completamente d'accordo, è solo un'opzione tecnicamente leggermente migliore rispetto all'altra risposta in alcuni scenari.
Oli,

Se stai reindirizzando il link verso un'altra destinazione, la modifica del suo numero di inode sembra una piccola modifica.
AMS

4
Ciò presuppone che linknamenon sia un collegamento simbolico a una directory. Usa l' -Topzione per mvse su GNU o -hse su FreeBSD per evitarlo. Si noti che in ln -sfquesto modo non si conservano le autorizzazioni del collegamento (sui sistemi in cui sono significativi).
Stéphane Chazelas,

Un'altra soluzione per il cambiamento link simbolico per la directory è quello di utilizzare -nle opzioni ad esempio: ln -sfn DESTINATION_DIRECTORY LINK_NAME. Maggiori informazioni su askubuntu.com/a/186227/69004
sobi3ch

22

Se per modifica, intendi cambiare il file a cui punta, quindi sì puoi:

$ 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

Il -fparametro ( --force) quando viene passato a ln fa sì che chiami prima la unlink()chiamata di sistemasymlink()

Tratto dalla seguente risposta di overflow dello stack .


9
Penso che sia discutibile se questo può essere considerato come "modifica", poiché unlink (); symlink (); non è atomico, quindi vi è una minuscola quantità di tempo durante la quale il collegamento non esiste.
replica il

@ mauro.stettler Sì, hai ragione. Ma immagino che questo dipenda dalla tua prospettiva. Se prendi in considerazione solo il risultato finale, forse potresti considerarlo come modificato, senza considerare altre cose.
NlightNFotis

1
La sezione citato dalla carta Unix System Time Sharing descrive duri link. Questi sono completamente diversi dai collegamenti simbolici (symlink) di cui l'OP ha chiesto.
Ansgar Esztermann,

4
Si noti che presuppone che testla destinazione non sia una directory. Altrimenti ln -s -f .profile testcreerebbe un .profilecollegamento simbolico in quella directory. GNU lnha -Tun'opzione per evitarlo.
Stéphane Chazelas,

9

I collegamenti simbolici devono essere modificati atomicamente. Se sei a metà della loro scrittura, non funzioneranno. Il contenuto di un collegamento simbolico è piuttosto piccolo (al massimo 4095 caratteri su Linux: la lunghezza massima di un percorso di un file), quindi sarebbe inutile modificare parte di un collegamento simbolico a livello di kernel. Pertanto il kernel non offre alcuna interfaccia per modificare un collegamento simbolico, solo un'interfaccia per crearne uno nuovo, la symlinkchiamata di sistema (più l'interfaccia generica unlinkper rimuovere qualsiasi file).

La symlinkchiamata di sistema crea solo un nuovo collegamento simbolico, non rimuove alcun file esistente. Questo è fastidioso, ma coerente con altre chiamate di sistema per creare file come open(che possono creare un nuovo file o troncare un file esistente, ma non sostituire un file esistente con un file appena creato) e mkdir.

Nella shell, come hai scoperto , mentre non puoi sostituire atomicamente un collegamento simbolico con il lncomando ( ln -sfscollega il file precedente, quindi crea il collegamento simbolico), puoi farlo creando prima un collegamento simbolico sotto un nome temporaneo e quindi spostandolo in posizione.

tmp=$(TMPDIR=$(dirname -- "$link") mktemp)
ln -sf -- "$target" "$tmp"
mv -f "$tmp" "$link"

2
mv -f(come ln -sf) non farà ciò che vuoi se $linkpunta a una directory. GNU ln e mv ne hanno una -T. mv(rinomina chiamata di sistema) cambierà sempre l'inode di $linkwhile ln -sfT(unlink + symlink) potrebbe riutilizzare lo stesso.
Stéphane Chazelas,

0

Tecnicamente, non esiste un comando integrato per modificare un collegamento simbolico esistente. Può essere facilmente raggiunto con alcuni brevi comandi.

Ecco una piccola funzione bash / zsh che ho scritto per aggiornare un collegamento simbolico esistente:

# -----------------------------------------
# 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"
}

Siamo spiacenti, ma la tua "risposta" è solo in remoto correlata alla domanda posta.
user2233709,

Ciao @ user2233709 - alla domanda dell'utente " Come posso modificare i link simbolici? " È stata data una risposta chiara nella prima frase e fornendo una soluzione. Ti andrebbe di elaborare?
blizzrdof77,

2
Hai davvero letto la domanda? Si tratta se è possibile modificare un collegamento simbolico, piuttosto che sostituirlo . La "soluzione" proposta è uno script che sostituisce un collegamento simbolico.
user2233709

0

Supponiamo che il nome link esista come risultato di averlo fatto (in passato):

 ln -s   /the/path/to/a/file   linkname

Quindi, ci sono tre modi per modificare il collegamento simbolico:

  • Usa ln con -fforza e anche per le directory -n(l'inode potrebbe essere riutilizzato):

    ln -sfn /some/new/path linkname
    
  • Rimuovi il link simbolico e creane uno nuovo (anche per le directory):

    rm linkname; ln -s /some/new/path linkname
    
  • crea un nuovo link simbolico, quindi mv(cambio atomico anche per le directory):

    ln -s  /some/new/path newlinkname
    mv -fT newlinkname linkname             # linkname remains after the command
    
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.