¿Cómo puedo eliminar archivos numerados en un rango determinado?

16

Tengo folderAque tiene algunos archivos con una secuencia numérica que comienza con a_000000. Lo que quiero hacer es eliminar archivos a partir de un número específico: digamos a_000750hasta el final de los archivos en esto folderA. ¿Alguien podría aconsejar cómo hacer esto usando el script de shell?

Tak
fuente
¿Puedo suponer que todos esos nombres de archivo tienen sufijos de 6 dígitos?
muru
sí lo son :) comienzan desde a_000000 hasta algún número
Tak
55
rm a_000[89]* a_0007[5-9]*?
Rinzwind
@Rinzwind, ¿podría explicar este comando?
Tak
2
@ user1460166 a_000[89]*incluye todos los archivos que comienzan con a_0008o a_0009, e a_0007[5-9]*incluye todos los archivos que comienzan con a_0007y luego contienen un número entre 5 y 9, seguido de cualquier cosa.
muru

Respuestas:

35

Suponiendo que sabe o puede adivinar el final del rango, puede usar expansiones de llaves :

rm a_{000750..000850}

Lo anterior eliminará los 101 archivos entre a_000750 y a_000850 inclusive (y se quejará de los nombres de archivo que se refieren a archivos no existentes). Si tiene demasiados archivos para eso, use find:

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

Aquí, findsimplemente enumera todos los archivos que coinciden a_*. La lista se pasa a un whilebucle donde cada nombre de archivo se lee en la variable $file. Luego, utilizando las funciones de manipulación de cadenas de bash , si la parte numérica (buscar imprime los archivos como ./file, por lo que solo ${file#./a_}imprime el número) es 000750o mayor, el archivo se elimina. El -vestá ahí para que pueda ver qué archivos se han eliminado.

Tenga en cuenta que lo anterior supone nombres de archivo sanos. Si sus nombres pueden tener espacios, líneas nuevas u otros caracteres extraños, use esto en su lugar:

find . -name 'a_*' -print0 | while IFS= read -rd '' file; do 
  [ "${file#./a_}" -gt 000749 ] && rm -v "$file" 
done
terdon
fuente
¿Por qué evitar [[?
muru
1
@muru ¿por qué usarlo? [[no simplifica las cosas aquí, [[ "${file#./a_}" > 000749 ]]por ejemplo, ni siquiera lo hace más corto. No me gusta usar sintaxis innecesaria y esta incluso funcionará en shells más simples como dash.
terdon
Porque [[maneja mejor los espacios y las rarezas (tampoco me importan demasiado >).
muru
1
@muru sí, pero [está bien si cita la variable como yo, funciona en muchos más shells y es más simple.
terdon
Si insistes. No es mi problema.
muru
3

Podrías hacer algo como esto:

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

El primer método asume un prefijo fijo, lo elimina y verifica el valor.

El segundo método supone un sufijo de longitud fija (y un prefijo fijo común) y se basa en ese hecho; y que, aunque 201viene antes 31en lexicografía, no lo hace antes 031.

Pruebe esto con el echocomando, y una vez que esté seguro de que enumera los archivos correctos, use rmen su lugar.

muru
fuente
ninguno de ellos está trabajando: /
Tak
@ user1460166 ah, probablemente se deba a la coincidencia de expresiones regulares. Lo actualizaré.
muru
sigue sin funcionar. por cierto, los archivos son .png :)
Tak
@ user1460166 ¿puedes decir cómo no funciona?
muru
Abro el terminal, coloco el CD en la carpeta, luego copio la línea y la pego, pero los archivos no se eliminan
Tak
0

Solución de shell POSIX

La primera solución de terdon se basa en la expansión de llaves , que es una propiedad de bashy ksh, sin embargo, no se puede usar en el /bin/shshell estándar , al que Ubuntu está vinculado /bin/dash.

En los casos en los que tiene que confiar /bin/shpara la portabilidad de sus scripts, generalmente hay dos formas de abordar esto. Uno sería a través de globbing. Justo cd folderAy desde allí corre rm a_*. La otra forma, sería implementar un estilo C para la alternativa de bucle usando while <CONDITION>;do ...donelenguaje de shell y formatear los números con printf:

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

Tenga en cuenta que aquí lo uso echo. Reemplace echo "$filename"con rm ./"$filename"o rm -- "$filename"cuando esté listo para eliminar los archivos. También tenga en cuenta que esto debe realizarse cuando ya ha cdeditado en el directorio deseado.

(ab) usando awk

Awk es un buen lenguaje tipo C que puede ayudarnos de dos maneras: (1) podemos generar nombres de archivo con for-loop y formatearlos mediante la sprintffunción, y (2) eliminar dichos archivos mediante un system()comando, que pasará nuestro nombre de archivo y rmcomando generados a /bin/sh:

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

Perl

Continuando con la idea del enfoque portátil donde "generamos" nombres de archivo, podemos hacer lo mismo en Perl:

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

Tan simple como

rm partialfilename* -f

En tu ejemplo es

rm a_00075* -f
Vitaly Dubyna
fuente
1
Lamento decirlo, pero eso no es un rango, esos son todos los archivos que comienzan con a_00075...
Fabby
1
* es un comodín, OP está buscando una respuesta sobre cómo eliminar una GAMA de cosas ... por ejemplo, si tenía archivos del 1 al 100 y quería eliminar del # 41 al # 75
Joshua Besneatte