Sostituisci collegamenti simbolici con file


31

Esiste un modo semplice per sostituire tutti i collegamenti simbolici con il file a cui si collegano?


3
Che problema stai cercando di risolvere?
Daniel Beck

3
Ho un sacco di collegamenti simbolici a un'altra unità. Ho bisogno di spostare tutti i file da quell'unità a cui si fa riferimento altrove in modo da poterlo rimuovere.
Marty Trenouth,

Risposte:


14

Per alcune definizioni di "facile":

#!/bin/sh
set -e
for link; do
    test -h "$link" || continue

    dir=$(dirname "$link")
    reltarget=$(readlink "$link")
    case $reltarget in
        /*) abstarget=$reltarget;;
        *)  abstarget=$dir/$reltarget;;
    esac

    rm -fv "$link"
    cp -afv "$abstarget" "$link" || {
        # on failure, restore the symlink
        rm -rfv "$link"
        ln -sfv "$reltarget" "$link"
    }
done

Esegui questo script con i nomi dei collegamenti come argomenti, ad esempio tramite find . -type l -exec /path/tos/script {} +


2
Grazie per la modifica, anon, ma lo script non fa i nomi dei file maniglia con spazi bene, citando le variabili in tutti i luoghi necessari. Passare "$var"a "${var}"è un noop in sh / bash. Ho rimosso l'uno bashism ( [[), il resto è compatibile con POSIX sh.
Grawity,

Un metodo ancora più efficace per gestire gli errori del collegamento simbolico è quello cpdi un file temporaneo nella stessa directory, quindi di mv -fquel file temporaneo nell'originale. Questo dovrebbe evitare problemi come persone che tengono premuto Ctrl-Co che il filesystem si riempie tra i comandi rme cp(impedendo così anche al nuovo lndi funzionare). I nomi di file temporanei sono facili da individuare ls -aper una successiva pulizia, se necessario.
Mr Fooz,

Come nota a margine, non riesco davvero a ricordare perché non ho usato solo abstarget=$(readlink -f "$link")il case case , ma potrebbe essere stato motivi di portabilità.
Grawity

17

Potrebbe essere più semplice usare tar per copiare i dati in una nuova directory.

-H      (c and r mode only) Symbolic links named on the command line will
        be followed; the target of the link will be archived, not the
        link itself.

Potresti usare qualcosa del genere

tar -hcf - sourcedir | tar -xf - -C newdir

tar --help:
-H, --format=FORMAT        create archive of the given format
-h, --dereference          follow symlinks; archive and dump the files they point to

1
Adoro la tua soluzione, ma non capisco l'ultima parte del tuo messaggio. Per me dovresti fare:tar -hcf - sourcedir | tar -xf - -C newdir
Seb DA ROCHA,

1
D'accordo, questa risposta dovrebbe essere aggiornata come da commento.
astabada,

1
cp -Lè la soluzione più semplice
plesiv

@plesiv true e posix-compliant, ma non tutte le cpimplementazioni copieranno le directory.
Wyatt8740,

16

Se ti ho capito correttamente, la -Lbandiera del cpcomando dovrebbe fare esattamente quello che vuoi.

Basta copiare tutti i collegamenti simbolici e li sostituirà con i file a cui puntano.


4
Grazie - quasi quello di cui avevo bisogno: dovevo fare qualcosa del genere: cp -L files tmp/ && rm files && cp tmp/files . se chiarisci, probabilmente aiuterai più persone ...
saggio

5

"facile" sarà una tua funzione, molto probabilmente.

Probabilmente scriverei uno script che utilizza l'utilità della riga di comando "trova" per trovare file collegati simbolicamente, quindi chiama rm e cp per rimuovere e sostituire il file. Probabilmente faresti bene ad avere anche l'azione chiamata da find check che c'è abbastanza spazio libero prima di spostare anche il link sym.

Un'altra soluzione potrebbe essere quella di montare il file system in questione attraverso qualcosa che nasconda i collegamenti sym (come samba), quindi copiare tutto da quello. Ma in molti casi, qualcosa del genere introdurrebbe altri problemi.

Una risposta più diretta alla tua domanda è probabilmente "sì".

Modifica: secondo la richiesta di informazioni più specifiche. Secondo la pagina man di find , questo comando elencherà tutti i file del link sym in una profondità di 2 directory, da /:

find / -maxdepth 2 -type l -print

( questo è stato trovato qui )

Per trovare trovare per eseguire qualcosa su trovarlo:

find / -maxdepth 2 -type l -exec ./ReplaceSymLink.sh {} \;

Credo che chiamerà alcuni script che ho appena creato e passerà il nome del file che hai appena trovato. In alternativa, è possibile acquisire l'output di ricerca su file (utilizzare "trova [blah]> symlink.data", ecc.), Quindi passare quel file a uno script scritto per gestire la copia sull'originale con garbo.


? Un po 'generico: puoi elaborarlo?
Linker3000,

2
La sintassi è-exec ./ReplaceSymLink.sh {} \;
gravità

Questo è andare per trovare gli elementi e quello contrassegnato come la risposta viene utilizzata per sostituire i collegamenti!
Marty Trenouth,

3

Questo è l'oneliner che ho usato: supponiamo che tutti i file locali siano collegamenti a un altro file in "sorgente". È possibile affinare la selezione dei file con motivi o "trova". Per favore, capisci prima di usare.

per f in *; do cp --remove-destination source / $ f $ f; fatto

Spero che sia di aiuto


che ne dici di usare readlink: for f in *; do cp ---- remove-destination "$ (readlink $ f)" "$ f"; fatto
Diego,

Sì, è una buona idea, ma perdi un po 'di controllo sull'operazione. Un limite della mia soluzione è che non funziona per i file con spazi vuoti nel mezzo o per elenchi molto lunghi. Probabilmente la soluzione finale è quella di mettere insieme il 'find --exec' sopra con il 'remove destination'. Qualcuno vuole provare?
MastroGeppetto,

gli spazi vuoti nel mezzo dovrebbero essere mitigati mettendo "$ f" tra virgolette doppie. Ecco come lo uso con "find & xargs" invece di "for loop": find ./ -type l -print0 | xargs -0 -n1 -i sh -c 'cp --remove-destination $ (readlink "{ } ")" {} "'L'ho pubblicato come risposta separata per la visibilità. superuser.com/a/1329543/499386
Diego

2
find . -type l -exec cp --dereference --recursive '{}' '{}'.dereferenced \;

Farà una copia di ogni file / cartella con collegamento simbolico in <filename>.dereferenced, che è più sicuro (se meno conveniente) rispetto alla semplice sostituzione diretta. Lo spostamento dei dati copiati nei nomi dei file dei link simbolici viene lasciato come esercizio per il lettore.


2

Utilizzando alcune delle idee precedenti, il seguente comando sostituirà ricorsivamente ogni collegamento simbolico con una copia dell'originale:

find . -type l -exec bash -c "echo 'Replacing {} ...';  cp -LR '{}' '{}'.dereferenced;  rm '{}';  mv '{}'.dereferenced '{}'" \;


1

Molte buone risposte lì, ma io da quando stavi cercando qualcosa di facile

for i in *; do link=$(readlink $i) && rm $i && mv $link $i; done

Un piccolo miglioramento aiuterà a trovare collegamenti simbolici: per lnk in `find. -tipo l`; do src = $ (readlink $ lnk) && rm $ lnk && mv $ src $ lnk; fatto (non testato con la gerarchia però, fai attenzione con i backtick)
Roman Susi,

1

Ho avuto lo stesso problema con la copia dei link di gwenview quando normalmente ti aspetteresti che segua il link e copi il file.

Quello che ho fatto per "ripulire" la directory seguendo tutti i collegamenti e copiando tutti i file puntati nella directory, è stato creare una directory scratch, eseguire ad es.

"for file in `ls`; do cp -L $file scratchdir/$file; done; mv scratchdir/* ./" 

questo è troppo pericoloso per essere inserito in uno script in quanto non vi è alcun controllo ma ha risolto il mio problema.



0

Ho fatto una versione di una riga, dal momento che il mio web-hotel non ha permesso script bash e ha funzionato bene per me:

before:
> find . -type l | wc -l
358

> for link in `find . -type l` ; do echo "$link : "; ls -al $link ; cp $link notalink; unlink $link; mv notalink $link ; ls -al $link; done
...

after:
> find . -type l | wc -l
0
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.