Eliminar archivos por expresión regular

Eliminar archivos por expresión regular

Quiero conservar los archivos cuyos nombres coincidan [0-9A-Z]{1,2}_\d{4}_\w+?\.dat, por ejemplo A1_2001_pm23aD.dat, K_1998_12.daty eliminar el resto.

Sin embargo, los comandos lsy rmno admiten dichas expresiones regulares. ¿Cómo puedo hacer esto?

Respuesta1

Usando globos extendidos:

shopt -s extglob
printf '%s\n' !([[:digit:][:upper:]]?([[:digit:][:upper:]])_[[:digit:]][[:digit:]][[:digit:]][[:digit:]]_+([[:alnum:]]).dat)

esto imprimirá todos los nombres de archivos/directorios que no !coincidan ( ) [[:digit:][:upper:]]seguidos de cero o uno [[:digit:][:upper:]]seguido de 4 [[:digit:]]entre _s y luego uno o más [[:alnum:]]antes de la extensión .dat.
Si desea buscar recursivamente:

shopt -s globstar
shopt -s extglob
printf '%s\n' **/!([[:digit:][:upper:]]?([[:digit:][:upper:]])_[[:digit:]][[:digit:]][[:digit:]][[:digit:]]_+([[:alnum:]]).dat)

Alternativamente, con gnu find(puedes usar una expresión regular):

find . -regextype egrep ! -regex '.*/[[:digit:][:upper:]]{1,2}_[[:digit:]]{4}_[[:alnum:]]+\.dat$'

Respuesta2

Hay muchas maneras de hacer esto. Podría utilizar un lenguaje de programación que comprenda expresiones regulares. Por ejemplo, en Perl:

perl -le 'unlink(grep(!/[0-9A-Z]{1,2}_\d{4}_\w+?.dat/,@ARGV))' *

Eso buscará todos los archivos (no subdirectorios) en el directorio actual, recopile aquellos que no coincidan con la expresión regular y elimínelos.

También puedes hacer algo similar con bash, solo necesitas traducir la expresión regular a POSIX ERE:

for f in *; do 
    [[ "$f" =~ [0-9A-Z]{1,2}_[0-9]{4}_[a-zA-Z0-9]+.dat ]] || rm "$f"; 
done

Tenga en cuenta que en su expresión regular, \w+?.datintentará hacer coincidir la cadena alfanumérica más pequeña posiblecualquier personajey dat. No veo por qué querrías usar +?aquí y probablemente quisiste usar \.dat. Supongo que probablemente también quieras asegurarte de que todo el nombre del archivo coincida, para que cosas como ésta foobarfoobarfoobarA1_2001_pm23aD.datfoobarfooabrtambién se eliminen. Si es así, utilice uno de estos en su lugar:

perl -le 'unlink(grep(!/^[0-9A-Z]{1,2}_\d{4}_\w+\.dat$/,@ARGV))' *

o

for f in *; do 
    [[ "$f" =~ ^[0-9A-Z]{1,2}_[0-9]{4}_[a-zA-Z0-9]+.dat$ ]] || rm "$f"; 
done

Finalmente, para eliminar también directorios, puedes hacer:

for f in *; do 
    [[ "$f" =~ ^[0-9A-Z]{1,2}_[0-9]{4}_[a-zA-Z0-9]+.dat$ ]] || rm -rf "$f"; 
done

Respuesta3

Puedes hacerlo con find:

find . -regextype posix-extended \
            -type f ! -regex '.*/[0-9A-Z]{1,2}_[[:digit:]]{4}_[[:alnum:]_]+?\.dat' -delete
  • Por supuesto, puedes ponerlo todo en una línea (eliminando el \al final de la primera línea).
  • -regextype posix-egrepParece funcionar exactamente tan bien como -regextype posix-extended.
  • Si su versión de findno es compatible -delete, utilice -exec rm -- {} +o -exec rm -- {} ';'.
  • Si desea buscar sólo en el directorio de nivel superior, utilice -maxdepth 1.

información relacionada