Come posso eliminare i file numerati in un determinato intervallo?


16

Ho folderAalcuni file con una sequenza numerica che inizia con a_000000. Quello che voglio fare è eliminare i file a partire da un numero specifico: diciamo a_000750fino alla fine dei file in questo folderA. Qualcuno potrebbe consigliarti come farlo usando lo script di shell?


Posso presumere che tutti questi nomi di file abbiano suffissi a 6 cifre?
muru,

si lo sono :) iniziano da a_000000 fino ad un certo numero
Tak

5
rm a_000[89]* a_0007[5-9]*?
Rinzwind,

@Rinzwind potresti per favore spiegare questo comando?
Tak

2
@ user1460166 a_000[89]*include tutti i file che iniziano con a_0008o a_0009e a_0007[5-9]*include tutti i file che iniziano con a_0007e quindi contengono un numero compreso tra 5 e 9, seguito da qualsiasi cosa.
muru,

Risposte:


35

Supponendo che tu sappia o possa indovinare la fine dell'intervallo, puoi utilizzare le espansioni del controvento :

rm a_{000750..000850}

Quanto sopra eliminerà i 101 file tra a_000750 e a_000850 inclusi (e si lamenterà dei nomi di file che si riferiscono a file inesistenti). Se hai troppi file per quello, usa find:

find . -name 'a_*' | while read file; do 
  [ "${file#./a_}" -gt 000749 ] && rm -v "$file" 
done

Qui, findsemplicemente elenca tutti i file corrispondenti a_*. L'elenco viene passato a un whileciclo in cui ogni nome di file viene letto nella variabile $file. Quindi, usando le funzionalità di manipolazione delle stringhe di bash , se la parte numerica (trova stampa file come ./file, quindi ${file#./a_}stampa solo il numero) è 000750o maggiore, il file viene eliminato. L' -vè proprio lì modo da poter vedere quali file sono stati rimossi.

Si noti che quanto sopra presuppone nomi di file sani. Se i tuoi nomi possono avere spazi, newline o altri caratteri strani, usa questo invece:

find . -name 'a_*' -print0 | while IFS= read -rd '' file; do 
  [ "${file#./a_}" -gt 000749 ] && rm -v "$file" 
done

Perché evitano [[?
Muru,

1
@muru perché usarlo? [[non semplifica le cose qui [[ "${file#./a_}" > 000749 ]]per esempio, non le rende nemmeno più brevi. Non mi piace usare sintassi inutili e questa funzionerà anche con shell più semplici come dash.
terdon,

Perché [[gestisce meglio gli spazi e le stranezze (non mi interessa molto >neanche per me ).
Muru,

1
@muru sì, ma [va bene se citi la variabile come ho fatto io, funziona su molte più shell ed è più semplice.
terdon,

Se insisti. Non è il mio problema.
Muru,

3

Potresti fare qualcosa del genere:

find . -regextype posix-extended -iregex './a_[0-9]{6}' -execdir bash -c '[[ ${1##./a_} > 000750 ]] && echo $1' "removing: " {} \;

O:

find . -regextype posix-extended -iregex './a_[0-9]{6}' | sort | sed '0,/000750/d' | xargs echo

Il primo metodo presuppone un prefisso fisso, lo rimuove e verifica il valore.

Il secondo metodo assume un suffisso a lunghezza fissa (e un prefisso fisso comune) e si basa su tale fatto; e che, mentre 201viene prima 31in termini lessicografici, non prima 031.

Provalo con il echocomando e una volta sicuro che elenca i file corretti, usa rminvece.


nessuno di loro sta lavorando: /
Tak

@ user1460166 ah, probabilmente è dovuto alla corrispondenza regex. Lo aggiornerò.
muru,

continua a non funzionare. a proposito, i file sono .png :)
Tak

@utente1460166 puoi dire come non funziona?
muru,

Apro il terminale, cd nella cartella quindi copio la linea e la incollo, ma i file non vengono eliminati
Tak

0

Soluzione shell POSIX

La prima soluzione di terdon si basa sull'espansione del controvento, che è una proprietà di bashe ksh, tuttavia, non può essere utilizzata nella /bin/shshell standard , a cui su Ubuntu è collegato un link simbolico /bin/dash.

Nei casi in cui devi fare affidamento /bin/shper la portabilità dei tuoi script, ci sono generalmente due modi per affrontarlo. Uno sarebbe tramite globbing. Appenacd folderA e da lì corri rm a_*. L'altro modo, sarebbe implementare uno stile C per l'alternativa del ciclo usando while <CONDITION>;do ...donenel linguaggio shell e formattare i numeri con printf:

$ sh -c 'i=0;while [ $i -le 750 ]; do filename=$(printf "a_%06d" $i);echo "$filename";i=$((i+1)) ;done'

Si noti che qui uso echo . Sostituisci echo "$filename"con rm ./"$filename"o rm -- "$filename"quando sei pronto per eliminare i file. Si noti inoltre che ciò dovrebbe essere eseguito quando si è già cdinseriti nella directory desiderata.

(ab) usando awk

Awk essendo un bel linguaggio simile a C può aiutarci in due modi: (1) possiamo generare nomi di file con for-loop e formattarli tramite la sprintffunzione, e (2) eliminare tali file tramite system()comando, che passerà il nostro nome di file generato erm comando a /bin/sh:

awk 'BEGIN{for(i=0;i<=750;i++){filename=sprintf("a_%06d",i);system("rm "filename);} }'

Perl

Continuando con l'idea dell'approccio portatile in cui "generiamo" nomi di file, possiamo fare lo stesso in Perl:

perl -le 'for(0..750){$fd=sprintf("a_%06d",$_);unlink($fd)}'

0

Semplice come

rm partialfilename* -f

Nel tuo esempio lo è

rm a_00075* -f

1
Mi dispiace dirlo, ma non è un intervallo, questi sono tutti file che iniziano con a_00075...
Fabby,

1
* è un carattere jolly, OP è alla ricerca di una risposta su come eliminare una GAMMA di cose ... ad es. se avevi i file da 1 a 100 e volessi cancellare da # 41 a # 75
Joshua Besneatte
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.