Come posso "ricollegare" molti link simbolici non funzionanti?


54

Ho un albero di directory, che ha un sacco di link simbolici ai file sotto /home... però mi sono trasferito /homead /mnt/homee hanno bisogno di un modo per "ricollegare" tutti i link simbolici. Esiste tale funzionalità o devo scrivere uno script per farlo?

Ad esempio, ho qualcosa di simile al seguente:

[root@trees ~]# ls -l /mnt/home/someone/something
total 4264
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 a -> /home/someone/someotherthing/a
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 b -> /home/someone/someotherthing/b
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 c -> /home/someone/someotherthing/c
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 d -> /home/someone/someotherthing/d
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 e -> /home/someone/someotherthing/e

/mnt/home/someone/something/subdir:
total 4264
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 a -> /home/someone/someotherthing/subdir/a
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 b -> /home/someone/someotherthing/subdir/b
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 c -> /home/someone/someotherthing/subdir/c
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 d -> /home/someone/someotherthing/subdir/d
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 e -> /home/someone/someotherthing/subdir/e

Voglio un comando che troverà tutti i collegamenti simbolici e ricollegherà negli stessi posti ma sotto /mnt/homeinvece di/home

Esiste un comando del genere?

Risposte:


55

Non esiste alcun comando per effettuare il retarget di un collegamento simbolico, tutto ciò che puoi fare è rimuoverlo e crearne un altro. Supponendo di disporre di utility GNU (ad es. In Linux non incorporato o Cygwin), è possibile utilizzare il -lnameprimario di findper abbinare i collegamenti simbolici in base al loro obiettivo e readlinkper leggere i contenuti del collegamento. Non testato:

find /mnt/home/someone/something -lname '/home/someone/*' \
     -exec sh -c 'ln -snf "/mnt$(readlink "$0")" "$0"' {} \;

Sarebbe meglio rendere relativi questi collegamenti simbolici. C'è una piccola utility conveniente chiamata symlinks(originariamente da Mark Lords, ora gestita da J. Brandt Buckley), presente in molte distribuzioni Linux. Prima dello spostamento, o dopo aver ripristinato i collegamenti validi come sopra, esegui symlinks -c /mnt/home/someone/somethingper convertire tutti i collegamenti simbolici assoluti nella directory specificata in collegamenti simbolici relativi a meno che non attraversino un confine del filesystem.


Senza offesa, questo è un ottimo one-liner, ma la sostituzione delle corde di Bash potrebbe probabilmente fare un po 'di magia per cambiare il percorso e sarebbe più facile.
0xC0000022L

@STATUS_ACCESS_DENIED In che modo? L'unica operazione di stringa è anteporre /mnta un percorso; non è necessaria alcuna operazione di stringa più elaborata della concatenazione.
Gilles 'SO- smetti di essere malvagio' l'

@Gilles: scusa, stavo pensando di più alla tua osservazione con i relativi percorsi. Per una "traduzione" esatta del tuo esempio hai ovviamente ragione.
0xC0000022L

13

So che questo non è esattamente ciò che l'autore sta chiedendo, ma sembra che abbiano già la loro risposta, quindi sto aggiungendo questo per altri come me che si imbattono nella domanda.

Quanto segue dovrebbe aiutare se è necessaria una soluzione più flessibile come avere un sacco di collegamenti simbolici rotti che possono essere riparati sostituendo parte degli obiettivi del collegamento simbolico.

per esempio. Dopo una modifica del nome utente, per sostituire il vecchio nome utente con il nuovo nome utente nella destinazione di molti collegamenti, dopo che la mossa era già stata eseguita. Crea uno script chiamato Replace-simlink mostrato di seguito:

#!/bin/bash
link=$1
# grab the target of the old link
target=$(readlink -- "$1")

# replace the first occurrence of oldusername with newusername in the target string
target=${target/oldusername/newusername}

# Test the link creation
echo ln -s -- "$target" "$link"

# If the above echo shows the correct commands are being issued, then uncomment the following lines and run the command again
#rm $link
#ln -s "$target" "$link"

e chiamalo con il seguente comando:

find /home/newusername/ -lname '/home/oldusername/*' -exec ~/bin/replace-simlinks {} \;

Spero che questo aiuti qualcuno

modifica: Grazie Gilles per il kickstart su questo script e per il suggerimento sull'uso dello script symlink per rendere i collegamenti relativi.


1
Trovo questa soluzione migliore perché utilizza una stringa di sostituzione, che aiuta nei casi in cui è necessario modificare il nome di una cartella nel mezzo del percorso. La soluzione è anche abbastanza facile da modificare per eseguire trasformazioni più complesse, se necessario.
Gallaecio,

Consiglio di citare gli argomenti alla sostituzione della stringa, poiché ciò deve essere fatto per usare le barre, ad es. Per il percorso nella domanda del PO. target=${target/"/home"/"/mnt/home"}Molto utile, comunque. Grazie.
Walter Nissen,

3

Crea /homecome collegamento simbolico a /mnt/homee tutti i collegamenti simbolici esistenti saranno nuovamente validi.


2
Il bind-mount tende spesso ad essere meno fragile dei symlink in scenari in cui i programmi sono a conoscenza dei symlink e agiscono in modo diverso a seconda del fatto ...
0xC0000022L
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.