
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.dat
y eliminar el resto.
Sin embargo, los comandos ls
y rm
no 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+?.dat
intentará 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.datfoobarfooabr
tambié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-egrep
Parece funcionar exactamente tan bien como-regextype posix-extended
.- Si su versión de
find
no es compatible-delete
, utilice-exec rm -- {} +
o-exec rm -- {} ';'
. - Si desea buscar sólo en el directorio de nivel superior, utilice
-maxdepth 1
.