2013-11-05 20 views
8

Sto provando a scrivere uno script di shell Bash molto semplice che eseguirà il cd in una directory specifica, rimuoverà tutti i file e le directory tranne alcuni selezionati e poi ritorna a la dir originaleScript Bash per rimuovere tutti i file e le directory eccetto quelli specifici

Il mio codice è:.

#!/bin/bash 
cd /path/to/desired/directory 
shopt -s extglob 
rm !\(filename1\|filename2\|filename3\) -rf 
cd - 

Ho provato molti modi diversi di scrivere i simboli '(' e '|', con virgolette singole o doppie o barra rovesciata ma niente ha funzionato nota, che shopt -s extglob e rm !(filename1|filename2) -rf funzionare bene al di fuori di uno script.

Probabilmente sto commettendo un livello e fondamentale errore di scripting bash che non riesco a vedere, ma l'esperienza è quello di venire ...

Qualche suggerimento !? Than ks in anticipo.

+0

State ottenendo alcun tipo di errori? – cforbish

+1

Sei sicuro che 'rm! (Nomefile1 | nomefile2) -rf' funzioni bene al di fuori di uno script? Mi sarei aspettato 'rm -rf! (Nomefile1 | nomefile2)' invece (con l'opzione prima degli operandi). – ruakh

+0

@ruakh Ho letto questo più volte. Sto anche usando le opzioni su 'rm' dopo i file di volta in volta. Forse è un po 'incoerente, ma ha sempre funzionato per me. @mario non è necessario tornare indietro alla directory con 'cd -' perché viene usata una subshell quando si esegue lo script. – EverythingRightPlace

risposta

7

Due problemi che posso vedere a destra fuori del blocco:

  • La -rf argomento per rm deve venire prima i nomi dei file
  • I prescrittori extglob !, (, | e ) dovrebbe non essere fuggito con i backslash

Prova a modificare:

rm -rf !(filename1|filename2|filename3) 

Se ancora non funziona, rimuovere l'argomento -f, e si otterrà i messaggi di errore di quello che sta andando male, invece di sopprimerli in silenzio. Per stampare il nome di ciascun file rimosso, puoi anche aggiungere l'opzione -v.

+0

solo per essere un po 'cauti dato che -rf rimuoverà i file senza chiedere e potrebbe esserci una seria perdita di dati – Ashish

+0

Ho trovato l'errore. Stavo confondendo bash con sh (la cui differenza ancora non capisco). rm -rf! (nomefile1 | nomefile2 | nomefile3) come pure rm! (nomefile1 | nomefile2 | nomefile3) - rf funzionano ugualmente bene all'esterno e all'interno dello script. Perché gli identificatori non devono essere contrassegnati con la barra rovesciata? –

+0

Continuo a ricevere 'bash:!: Evento non trovato' con bash 4.3.11. Sembra che mi sono dimenticato di aggiungere la linea shopt. – tarabyte

0

Prova di seguito:

for i in `ls | grep -v "file1\|file2\|file3"` ; do rm -rf $i; done 

Good Luck!

+0

Si noti che questo non funzionerà in tutti i modi se si dispone di spazi nei nomi di cartelle o file. Inoltre non funziona con le sottocartelle. –

+0

@Aaron Digulla per quanto riguarda gli spazi, prova questo: for i in 'ls | grep -v '"nuova cartella" \ | file2 \ | file3''; fai rm -rf $ i; fatto – Nancy

+0

1. Hai bisogno di quotazioni intorno a '$ i', anche. 2. "nuova cartella" sarà divisa da 'for' in' new' e 'folder'. –

3

Se si dispone di una versione recente di find, quindi utilizzare:

find . -not -regex "filename1|filename2|filename3" -print 

controllare l'output e sostituire -print con -delete se la stampa solo i file che si desidera cancellare.

Se la versione di find non supporta -delete, utilizzare -type f -exec rm "{}" \;

Si noti che questo cancellerà solo i file. Questo è importante: se si dice di mantenere il file x ma quel file si trova in una cartella , quindi ignorerebbe x solo per eliminarlo in seguito con l'intera cartella .

di sbarazzarsi di tutte le cartelle vuote (e questo preservando i file che si desidera conservare):

find . -type d -empty -exec rmdir "{}" \; 

(fonte: How to Find and Delete Empty Directories and Files in Unix)

0

Non consiglio cercando di scrivere una regola per Escludere file specifici. Quello che avrei più probabilità di fare sarebbe cercare di trovare una maschera/glob o qualche altra ancora nei nomi dei file che vuoi rimuovere, che i file che vuoi mantenere, non hanno. Nella maggior parte dei casi, potresti probabilmente farlo per estensione. Sfortunatamente, poiché non hai menzionato il nome di nessuno dei file, non posso aiutarti in modo più specifico.

Qualcosa di simile a due (o più) trovare loop: -

find *.mp3 d.mp3 -maxdepth 1 -type f | while read mp3s 
do 
mv $mp3s ~/d.stuff-to-keep 
done  

find *.txt d.mp3 -maxdepth 1 -type f while read textfiles 
do 
rm -v $textfiles 
done 

In caso contrario, cercare qualche altra caratteristica comune dei file. Se non ce n'è uno, potrebbe essere necessario rinominare i file per dartene uno. Ho sempre inserito molti ancore (campi di nomi separati, estensioni ecc.) Nei miei nomi di file, perché in questo modo ho molti modi diversi per fare ciò che mi serve con loro. Il mio solito formato del nome è: -

<extension>.+<author>+<year>+<work-name>+<volume-number>+<number-of-volumes> 

Inoltre segni sono separatori di campo, trattini sono per gli spazi, ma senza trattini come sia primo o ultimo carattere. Tutte le lettere minuscole e nessun carattere di controllo o altri non-alfanumerici consentiti. Di conseguenza, posso eliminarli con awk, cut o qualsiasi altra cosa potrei voler usare e rinominarli facilmente. Mettere l'estensione all'inizio del nome significa anche che è necessario un solo flag (-l) per ottenere un file system perfettamente ordinato.

Se si sa come utilizzare la struttura di directory come un database con gli strumenti POSIX di base, a volte non è necessario installare qualcosa di più complicato, al fine di fare ciò che si desidera.

Hai un lungo limite per i nomi di file in UNIX, oltre al completamento della scheda per navigare tra nomi lunghi. Non aver paura di fare un uso liberale di entrambi.

0

a patto di avere i file:

drwxr-xr-x 2 root root 4096 1 Febbraio 02:17 una radice

drwxr-xr-x 2 radice 4096 Feb 1 02:17 b

drwxr-xr-x 2 root root 4096 feb 1 02:17 c

radice drwxr-xr-x 2 radice 4096 feb 1 2:17 d

drwxr-xr-x 2 radice roo t 4096 feb 1 02:17 e

radice drwxr-xr-x 2 radice 4096 feb 1 2:17 f radice

drwxr-xr-x 2 radice 4096 feb 1 02:18 nodelete1

drwxr-xr-x 2 root root 4096 1 Febbraio 02:18 nodelete2

Si potrebbe fare:

ls | grep -v "nodel.\+" | xargs rm -rf

a usa la sintassi regexp avanzata per escludere i file.

Spiegazione:

ls --- elenca directory corrente (ls -d per elencare solo le directory)

grep -v --- v flag specifica che cosa non corrispondere + grep permette di scrivere in stile Perl regexp se si fornisce -P bandiera

xargs --- applica azione "rm-rf" su ciascuno degli elementi

Problemi correlati