Elimina tutti i file in una directory il cui nome non corrisponde a una riga in un elenco di file


9

Ho una directory con oltre 1000 file. In un file di testo, ho circa 50 nomi di file, uno per riga. Vorrei eliminare tutti i file nella directory i cui nomi di file non corrispondono a una voce dell'elenco. Qual'è il miglior modo per farlo? Ho avviato uno script di shell, ma non sono riuscito a determinare il comando corretto da determinare nel nome file nell'elenco. Grazie.

Risposte:


8

Mi rendo conto che qualsiasi domanda che chieda come eliminare i file deve essere presa con grande cura. La mia prima risposta fu troppo frettolosa, non pensai che la filelist potesse essere malformata per essere usata con egrep. Ho modificato la risposta per ridurre tale rischio.

Dovrebbe funzionare per i file che non hanno spazio nel nome:

Prima ricostruisci la tua lista di file per essere sicuro che corrisponda al nome esatto del file:

sed -e 's,^,^,' -e 's,$,$,'  filelist  > newfilelist 

crea i comandi rm

cd your_directory
ls | egrep -vf newfilelist   | xargs -n 1 echo rm  >  rmscript

Controlla se lo script rm è adatto a te (puoi farlo con "vim" o "less").
Quindi eseguire l'azione:

sh -x rmscript

Se i file hanno spazi nel loro nome (se i file hanno "il nome, questo non funzionerà):

ls | egrep -vf newfilelist  | sed 's,^\(.*\)$,rm "\1",' > rmscript

ovviamente la filelist non dovrebbe trovarsi nella stessa directory!

MODIFICATO :

L'elenco dei file di Nathan conteneva nomi che corrispondevano a tutti i file nella directory (come "html" corrisponde a "bob.html"). Quindi nulla è stato cancellato perché ha egrep -vfassorbito tutto il flusso. Ho aggiunto un comando per inserire un "^" e un "$" attorno a ciascun nome di file. Sono stato fortunato qui che l'elenco dei file di Nathan era corretto. Se fosse stato formattato DOS con le linee finali CR-LF o con spazi aggiuntivi, nessun file sarebbe stato conservato da egrep e sarebbe stato cancellato.


Quando eseguo il comando di anteprima, ottengo una riga con "rm". Quando eseguo il comando effettivo, viene visualizzato un messaggio di errore relativo agli argomenti mancanti per rm. Ho bisogno di una sintassi speciale per usare i risultati di ls | egrep nell'input di xargs?
Nathan,

@Nathan devi prima cd nella tua directory. Nessuna sintassi speciale. lsfornisce i nomi dei file di directory, egrep -vf filelistfiltra i tuoi 50 nomi di file. Temo che tu abbia eliminato tutti i tuoi file.
Emmanuel,

@Emamanuel Sto eseguendo il comando dalla directory che contiene i file da eliminare.
Nathan,

@Nathan sono stati cancellati tutti i tuoi file?
Emmanuel,

no, sono ancora lì.
Nathan,

1

Pre-costruire gli argomenti per find:

{
  read -r
  keep=( -name "$REPLY" ) # no `-o` before the first one.
  while read -r; do
    keep+=( -o -name "$REPLY" )
  done
} < file_list.txt
find . -type f ! \( "${keep[@]}" \) -exec echo rm {} +

Usa le echoparti per vedere cosa sarebbe stato costruito. Rimuovere le echoparti per eseguirlo effettivamente.

Aggiornamento: dimostrazione:

##
# Demonstrate what files exist for testing.
# Show their whitespace:
~/foo $ printf '"%s"\n' *
" op"
" qr"
"abc"
"def"
"gh "
"ij "
"k l"
"keep"
"m n"

##
# Show the contents of the "keep" file,
# Including its whitespace:
~/foo $ cat -e keep
keep$
abc$
gh $
k l$
 op$

##
# Execute the script:
~/foo $ { read -r; keep=( -name "$REPLY" ); while read -r ; do keep+=( -o -name "$REPLY" ); done } < keep
~/foo $ find . -type f ! \( "${keep[@]}" \) -exec rm {} +

##
# Show what files remain:
~/foo $ printf '"%s"\n' *
" op"
"abc"
"gh "
"k l"
"keep"

mi piace di più, in quanto elimina la necessità di fare la filelist
eyoung100

+1 da me, anche se non si occupa molto bene degli spazi. Forse alcune virgolette singole ( ') dovrebbero essere aggiunte ie keep=( -name \'"$REPLY"\' )e keep+=( -o -name \'"$REPLY"\' ).
Cristian Ciupitu,

quanto sopra è pericoloso, perché è possibile eliminare file accidentalmente.
davidva,

@CristianCiupitu non è vero? Ho aggiunto una demo che mostra che si occupa molto bene degli spazi bianchi.
Kojiro,

@davidva In quali circostanze? Ogni volta che automatizzi la cancellazione di cose corri il rischio di fare un errore, ma secondo i parametri della domanda penso che la mia demo dimostri che questo approccio è valido.
Kojiro,

1

Con zsh:

mylist=(${(f)"$(<filelist)"})
print -rl -- *(.^e_'(($mylist[(Ie)$REPLY]))'_)

Legge le righe di filelistin un array e quindi usa i qualificatori / estring di glob per glob / seleziona solo i nomi di file non presenti nell'array: .seleziona solo i file regolari (aggiungi Dse la tua lista contiene dotfile) e il negato ^e_'expression'_seleziona ulteriormente solo quelli per che l'espressione restituisce false, ovvero se il loro nome ( $REPLY) non è un elemento dell'array .
Se sei soddisfatto del risultato, sostituiscilo print -rlcon rmper rimuovere effettivamente i file:

rm -- *(.^e_'(($mylist[(Ie)$REPLY]))'_)

Per selezionare e rimuovere i file in modo ricorsivo, utilizzare il */**glob con ${REPLY:t}modificatore glob:

rm -- */**(.^e_'(($mylist[(Ie)${REPLY:t}]))'_)

0

Se metti il ​​contenuto della directory in un file in questo modo:

cd <somedirectory>
ls >> filelist

Apri la filelist con un editor di testo e rimuovi tutti i file tranne quelli che VUOI ELIMINARE . Questo è in grassetto perché è l'approccio opposto alla risposta sopra

Prova questo:

while read p || [[ -n $p ]]; 
echo $p
done < filelist

Se vedi il tuo elenco di file in uscita sullo schermo, sostituisci l'eco con rm -v, in questo modo:

while read p || [[ -n $p ]]; 
rm -v $p
done < filelist

0

Esegui lo script seguente.

  1. Inizialmente sto trovando tutti i file presenti nella directory e archiviando l'output in un altro file all_files.
  2. Abbiamo un file che ha l'elenco dei file che NON devono essere eliminati ( not_to_be_deleted_files).
  3. Sto aggiungendo i nomi dei file not_to_be_deleted_filese files_to_be_deletedalla fine di not_to_be_deleted_filescome abbiamo bisogno di questi 2 file.
  4. Ora sto trovando i file che devono essere cancellati usando il joincomando linux e reindirizzando l'output su files_to_be_deleted file.
  5. Ora, nel ciclo while finale, sto leggendo tutti i nomi dei file files_to_be_deletede rimuovendo i file menzionati in quel nome.

Lo script è come di seguito.

find /home/username/directory -type f | sed 's/.*\///' > all_files
echo all_files >> not_to_be_deleted_files
echo not_to_be_deleted_files >> not_to_be_deleted_files
echo files_to_be_deleted >> not_to_be_deleted_files
join -v 1 <(sort all_files_listed) <(sort files_not_to_be_deleted) >   files_to_be_deleted
while read file
rm  "$file"
done < files_to_be_deleted

PS : Probabilmente, se desideri che questo venga salvato come script ed eseguilo, puoi aggiungere anche il nome dello script usando echo scriptname >> not_to_be_deleted_files.

Anche se non è richiesto, preferisco farlo perché non ci saranno rimpianti in seguito. Ho provato per un piccolo set di file e ha funzionato nel mio sistema. Tuttavia, se si desidera essere sicuri, provare prima in una testdirectory, quindi rimuovere i file nella directory originale.


0
  • Utilizzare l'elenco come origine per spostare tutti i file dell'elenco in una directory di salvataggio nuova, nuova e vuota.
  • Confronta il numero di file nell'elenco e il numero di file salvati.
  • Se entrambi corrispondono, elimina tutti i file non salvati con il tuo metodo preferito.
  • Sposta indietro i file salvati.

0

Ho optato per un approccio più sicuro e molto, molto più veloce perché avevo 18.000 file nell'elenco! Avevo bisogno di ripulire le immagini in una grande installazione di Drupal.

L'eliminazione di tutti i file non presenti nell'elenco equivale a conservare solo quelli presenti nell'elenco. Così ho deciso di copiare effettivamente i file dall'elenco in un'altra posizione, ma la copia di 20 GB di file occuperebbe troppo spazio e sarebbe anche molto lenta. Quindi il trucco è copiare i file come hardlinksinvece, usando l' -lopzione di cp. Questo non occupa quasi spazio ed è molto veloce. Inoltre, poiché avevo bisogno di preservare la struttura delle directory, ho usato l' --parentsopzione.

Ecco un estratto dal mio elenco di file:

1px.png
misc/feed.png
modules/file/icons/x-office-presentation.png
modules/file/icons/x-office-spreadsheet.png
newsletter.png
sites/all/libraries/ckeditor/plugins/smiley/images/devil_smile.png
sites/all/libraries/ckeditor/plugins/smiley/images/regular_smile.png
sites/default/files/009313_PwC_banner_CBS_Observer_180x246px.jpg

Quindi una riga di esempio sarebbe, con temp come destinazione:

cp -l --parents 'misc/feed.png' temp

Questo creerà questa struttura:

temp
  misc
    feed.png

Si noti che il destino deve trovarsi nello stesso file system dell'origine affinché i collegamenti fisici funzionino.

Il prossimo passo è costruire lo script:

sed -e "s,^,cp -l --parents '," -e "s,$,' /some/where/temp," filelist > newfilelist

Ora, supponendo che tu abbia già creato la directory vuota / some / where / temp, puoi copiare i file in questo modo:

sh newfilelist 2> missing_files

Nota come finiscono gli errori missing_files. Il vantaggio aggiuntivo di questo approccio è che otterrai un elenco di file dall'elenco originale che in realtà non esistono!

Dopo aver eseguito lo script, temp conterrà solo i file presenti nell'elenco dei file, ma senza eliminare nulla e senza occupare spazio aggiuntivo. Se sei soddisfatto del risultato, puoi eliminare tutti i file originali comprese le sottocartelle.

Infine, sposta i file e le cartelle dalla temp alla posizione originale.

Per i 18.000 file ci sono voluti solo pochi secondi.


0

Sicuro, semplice

cd alla directory.

Creare una directory temporanea.

mv *.yourExlusionSelector.* ./temp
rm *
mv ./temp ./
rm -rf ./temp

fatto.


Benvenuti nel sito. Mentre il vostro approccio funzionerà se i nomi nell'elenco menzionato dall'OP sono il risultato di una semplice corrispondenza del modello - che può benissimo essere il caso - si noti che l'OP ha dichiarato che i nomi dei file da escludere sono memorizzati in un file specifico; potresti voler espandere la tua risposta in modo da leggere i pattern di esclusione da quel file invece di fare affidamento su un pattern statico o dover copiare i pattern potenzialmente multipli sulla console.
AdminBee,
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.