Rimuovi il file, ma solo se si tratta di un link simbolico


11

Idealmente, vorrei un comando come questo

rm --only-if-symlink link-to-file

perché mi sono bruciato troppe volte eliminando accidentalmente il file anziché il collegamento simbolico che punta al file. Questo può essere particolarmente negativo quando è coinvolto sudo. Ora, ovviamente, faccio una cosa ls -alper assicurarmi che sia davvero un link simbolico e simili, ma che è vulnerabile all'errore dell'operatore (nome simile di file, errore di battitura, ecc.) E alle condizioni di gara (se qualcuno volesse che eliminassi un file per qualche motivo). C'è un modo per verificare se un file è un collegamento simbolico ed eliminarlo solo se si trova in un comando?


1
Non penso che le condizioni di gara debbano essere fonte di preoccupazione. Chiunque sia in grado di rimuovere il link simbolico e sostituirlo con un file avrebbe bisogno dell'autorizzazione di scrittura sulla directory, il che significa che potrebbe anche eliminare il file da solo.
Nate Eldredge,

Risposte:


19
 $ rm_if_link(){ [ ! -L "$1" ] || rm -v "$1"; }

 #test
 $ touch nonlink; ln -s link
 $ rm_if_link nonlink
 $ rm_if_link link
   removed 'link'     

4
Sicuramente sarebbe più chiaro rimuovere !e cambiare ||in&&
glenn jackman

5
@glennjackman Ho preso l'abitudine di preferire il ||modulo. &&abbassa le cose se sei in set -emodalità.
PSkocik,

@PSkocik Questo è rischioso in generale poiché non distingue tra il caso interessante (il file esiste ed è un collegamento simbolico) e altri motivi per un codice di uscita diverso da zero, come un valore vuoto non quotato ( [ ! -L $1 ]), utilizzando un operatore non valido ( [ ! -l foo ]) o errore di sintassi ( [ ! -q foo || echo foo)
l0b0

2
@XiongChiamiov Il problema rm_if_link(){ [ -L "$1" ] && rm -v "$1"; }è che eseguirlo su un nonlink in set -e modalità ucciderà il processo della shell. Potresti aggiungere || :ma poi diventa, IMHO, ancora meno chiaro della ! ||versione, e impedirà a un rmfallimento di ucciderti set -e, il che è probabilmente indesiderabile. ! ||è abbastanza conciso e chiaro e non soffre di nessuno di questi problemi.
PSkocik,

1
Nope . Altre opzioni: a) inserisci l' rminterno del tuo test, b) usa un'istruzione if effettiva, c) non andare in giro usando -eall'interno di shell interattive (e prova i tuoi script!). Se vuoi discutere di leggibilità, usare ifper verificare se qualcosa è un link è abbastanza chiaramente il vincitore.
Boicottaggio SE per Monica Cellio,

5

È possibile utilizzare finde la sua -type lcondizione di test (che controlla se l'oggetto trovato è un l inchiostro o no)

Ad esempio, se hai un file chiamato foonella directory corrente, puoi farlo:

$ find . -type l -iname "foo" -delete

Potresti essere in grado di semplificarlo con solo:

$ find . -maxdepth 1 -type l -delete

Che eliminerebbe tutti i collegamenti simbolici nella directory corrente.

Avvertimento:

L' -deleteopzione in findè davvero pericolosa. ASSICURARSI DI EFFETTUARLO ALLA FINE DEL COMANDO TROVARE. Se lo perdi, eliminerà tutto ciò che trova indipendentemente dal fatto che i risultati corrispondano al tuo condizionale.

Come suggerito nei commenti, un'opzione più sicura potrebbe essere l'uso finde rm -i(che ti costringe a confermare la rimozione del file) in combinazione:

$ $ find . -type l -iname "foo" | xargs rm -i

Personalmente uso -exec trash {} \;per eliminare temporaneamente i file, perché io, come te, sono stato masterizzato rmin passato. Il doppio vale per una -deletebandiera fuori posto .

http://slackermedia.ml/trashy


1
Invece di -delete puoi semplicemente stamparlo e passarlo a xargs: find . -type l -iname "foo" | xargs rm -i è più sicuro.
Boban P.

1
Mi piace l'uso di@BobanP. rm -iper sicurezza, di sicuro.
Klaatu von Schlacker,

3
"Questo eliminerebbe tutti i collegamenti simbolici nella directory corrente" ... e qualsiasi punto sottostante.
Joseph R.

1
Come @JosephR. detto, andrà fino in fondo alla strada. Aggiungi -maxdepth 1 in find.
Boban P.

1
Si rompe ancora sui nomi di file con spazi. Suggerisci di usare -print0per finde -0per xargs.
Wildcard il

4
zsh -c 'rm foo(@)'

@è un qualificatore glob ; lo schema foo(@)corrisponde a ciò che foocorrisponde, ma solo ai collegamenti simbolici.

foo(-@)corrisponderebbe solo a collegamenti simbolici interrotti. foo(@,L0)corrisponderebbe solo a collegamenti simbolici e file vuoti.

Ovviamente, se stai eseguendo zsh in primo luogo, devi solo digitare rm foo(@). È necessario fare attenzione a non premere Enterprima di digitare (@).


1
Zsh sembra sempre più potente quando vedo risposte come questa.
Jeff Schaller
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.