TL; DR: il modo migliore è usare al -exec rm
posto di -delete
.
find a \( -name b -prune \) -o -type f -exec rm {} +
Spiegazione:
Perché trovare lamentarsi quando si tenta di utilizzare -delete
con -prune
?
Risposta breve: perché -delete
implica -depth
e -depth
rende -prune
inefficace.
Prima di arrivare alla lunga risposta, osservare innanzitutto il comportamento di find con e senza -depth
:
$ find foo/
foo/
foo/f1
foo/bar
foo/bar/b2
foo/bar/b1
foo/f2
Non esiste alcuna garanzia sull'ordine in una singola directory. Ma c'è una garanzia che una directory viene elaborata prima del suo contenuto. Nota foo/
prima di qualsiasi foo/*
e foo/bar
prima di qualsiasi foo/bar/*
.
Questo può essere invertito con -depth
.
$ find foo/ -depth
foo/f2
foo/bar/b2
foo/bar/b1
foo/bar
foo/f1
foo/
Nota che ora foo/*
appaiono tutti prima foo/
. Lo stesso con foo/bar
.
Risposta più lunga:
-prune
impedisce a find di scendere in una directory. In altre parole, -prune
salta il contenuto della directory. Nel tuo caso -name b -prune
impedisce a find di scendere in qualsiasi directory con il nome b
.
-depth
fa trovare per elaborare il contenuto di una directory prima della directory stessa. Ciò significa che nel momento in cui find riesce a elaborare la voce della directory, il b
suo contenuto è già stato elaborato. Quindi -prune
è inefficace con -depth
in effetti.
-delete
implica -depth
quindi in grado di eliminare prima i file e poi la directory vuota. -delete
si rifiuta di eliminare le directory non vuote. Immagino che sarebbe possibile aggiungere un'opzione per forzare -delete
l'eliminazione di directory non vuote e / o per impedire -delete
che ciò implichi -depth
. Ma questa è un'altra storia.
C'è un altro modo per ottenere ciò che vuoi:
find a -not -path "*/b*" -type f -delete
Questo può essere o non essere più facile da ricordare.
Questo comando scende ancora nella directory b
e procede ogni singolo file in essa contenuto solo per -not
rifiutarli. Questo può essere un problema di prestazioni se la directory b
è enorme.
-path
funziona diversamente da -name
. -name
corrisponde solo al nome (del file o della directory) mentre -path
corrisponde all'intero percorso. Ad esempio osservare il percorso /home/lesmana/foo/bar
. -name -bar
corrisponderà perché il nome è bar
. -path "*/foo*"
corrisponderà perché la stringa /foo
è nel percorso. -path
ha alcune complessità che dovresti capire prima di usarlo. Leggi la pagina man di find
per maggiori dettagli.
Attenzione che questo non è sicuro al 100%. Ci sono possibilità di "falsi positivi". Il modo in cui il comando è scritto sopra salterà qualsiasi file che ha una directory padre con il nome che inizia b
(positivo). Ma salterà anche qualsiasi file con il nome che inizia con b
indipendentemente dalla posizione nella struttura (falso positivo). Questo può essere risolto scrivendo un'espressione migliore di "*/b*"
. Questo è lasciato come esercizio per il lettore.
Presumo che tu abbia usato a
e b
come segnaposto e i nomi reali siano più simili allosaurus
e brachiosaurus
. Se lo metti brachiosaurus
al posto di b
allora la quantità di falsi positivi verrà drasticamente ridotta.
Almeno i falsi positivi non saranno cancellati, quindi non sarà così tragico. Inoltre, è possibile verificare la presenza di falsi positivi eseguendo prima il comando senza -delete
(ma ricordarsi di posizionare l'implicito -depth
) ed esaminare l'output.
find a -not -path "*/b*" -type f -depth
a
trannea/b
?