Recupera todos los nombres de archivos con un número específico de caracteres

Recupera todos los nombres de archivos con un número específico de caracteres

Quiero cambiar todos los nombres de archivos, ya que tienen la longitud exacta de 16 caracteres (dígitos y letras minúsculas). Probé [0-9a-z]{16}y [0-9a-z]\{16\}para el marcador de posición regXen el siguiente fragmento, pero no funciona.

for file in <regX>
do
  mv "$file" "${file}.txt"
done

Respuesta1

Patrones globulares de conchasno son expresiones regulares. Pueden parecer similares, pero funcionan de manera bastante diferente en algunos aspectos.

La expresión regular [0-9a-z]{16}coincide con una cadena que contiene una serie de 16 caracteres del rango de caracteres mencionado (la cadena que contiene la coincidencia puede ser más larga).

El patrón de globo de caparazón equivalente sería algo así como

*[0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z]*

Esto es porque

  1. Los patrones globales no admiten modificadores que digan "repetir las N veces anteriores".
  2. Los patrones globales están anclados de forma predeterminada al principio y al final. Por eso lo inserté *al principio y al final del patrón. A *coincide con cualquier número de cualquier carácter. Elimínalos si quieres que coincidanexactamente16 caracteres.

Puedes crear una cadena de 16 [0-9a-z]usando Perl:

$ pattern="$( perl -e 'print "[0-9a-z]" x 16' )"

Con bash, puede optar por iterar sobre todos los nombres en el directorio actual y luego probar si los nombres coinciden con su expresión regular:

for name in *; do
    if [[ -f "$name" ]] && [[ "$name" =~ ^[0-9a-z]{16}$ ]]; then
        echo mv "$name" "$name.txt"
    fi
done

Elimínelo echouna vez que sepa que está haciendo lo correcto.

Observe que he anclado el patrón para que los nombres más largos no coincidan. También me aseguro, con la -fprueba, de que los nombres que obtenemos sean en realidad únicamente los de archivos normales.

Respuesta2

Conextglob

shopt -s extglob
for file in +([0-9a-z])
do
    [[ ${#file} == 16 ]] && echo mv "$file" "${file}.txt"
done
  • +([0-9a-z])significa uno o más [0-9a-z]caracteres
  • ${#file}da la longitud del nombre del archivo
  • echoes para funcionamiento en seco, retírelo una vez que todo esté bien

Respuesta3

Si tiene perl-rename (llamado renameen sistemas basados ​​en Debian, perl-renameen otros), puede hacer:

perl-rename -n 's/^[0-9a-z]{16}$/$&.txt/' *

Si eso hace lo que desea, elimine el -npara que realmente cambie el nombre de los archivos. La sintaxis de perl-renamees un comando de Perl. Aquí, estamos usando el operador de sustitución ( s/from/to/) que reemplazará fromcon to. En fromeste caso, es su expresión regular y toes la variable especial $&que significa "lo que coincidió", más la extensión .txt.


Para hacer esto con un globo de shell (use@Kusalanandao@Deep del Solenfoque, esto es sólo para completar):

for f in [0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z]; do
    mv -- "$f" "$f".txt
done

Con GNU find:

find . -regextype posix-extended -regex '.*/[0-9a-z]{16}' -exec mv {} {}".txt" \;

Respuesta4

L16=$(csh -c 'repeat 16 echo -n "?"')
find . -name "$L16" ! -name '*[!0-9a-z]*' -exec sh -c '
   mv "$1" "$1.txt"
' {} {} \;

información relacionada