Script de Shell para cambiar el nombre de varios archivos a partir del nombre de sus carpetas principales

Script de Shell para cambiar el nombre de varios archivos a partir del nombre de sus carpetas principales

Tengo una estructura de archivos como esta:

  • 00000010
    • 000000001.archivo1
    • 000000001.archivo2
  • 00000020
    • 00000003.archivo1
    • 00000003.archivo2
    • 00000003.archivo3
  • ...

Entonces, hay carpetas con nombres de 8 dígitos que contienen uno o más archivos con nombres que comienzan con números de 8 dígitos. Pero estos nombres de archivos están, digamos, no sincronizados. Ahora intento cambiarles el nombre de forma recursiva en bash para archivarlos:

  • 00000010
    • 000000010.archivo1
    • 000000010.archivo2
  • 00000020
    • 00000020.archivo1
    • 00000020.archivo2
    • 00000020.archivo3
  • ...

Mi guión se parece a:

#! /bin/bash

find * -maxdepth 1 -name "*" -type d | while read -r dir
do
        rename 's/$dir\/[0-9]{8}/$dir/' *
done

Pero esto no funciona y da errores como

El símbolo global "$dir" requiere un nombre de paquete explícito en (eval 1) línea 1.

¿Cómo podría escribirlo para cambiar el nombre de los archivos según los nombres de sus carpetas?

¡Gracias por ayudar!

Respuesta1

A partir de otra respuesta aprendí que tengo que usar

rename "s/$dir\/[0-9]{8}/$dir\/$dir/" $dir/*

Por si alguien tiene el mismo problema...

Respuesta2

Realmente no me gusta la respuesta donde $dirse interpola en el patrón. Podría generar resultados inesperados si el directorio contuviera, por ejemplo, un carácter que se interpreta como un token de expresión regular especial.

Preferiría hacer coincidir los archivos directamente en el patrón, eliminando la necesidad de recorrer los directorios y simplemente usar un globo normal.

rename 's#([^/]+)/[^/]+(\.file[0-9]+)$#$1/$1$2#' base_directory/*/*

donde el globo llega a los archivos individuales dentro de los directorios (incluso podría especificarse como base_directory/*/*.file*, o similar, pero no debería importar aquí).

Tenga en cuenta que este es el comando completo, sin necesidad de findconstrucción.

  • Lo uso #como separador en lugar del "normal" /para evitar tener que escapar de eso en los patrones.
  • Capturo el grupo (codicioso) de "no es un separador de directorio", seguido de un separador de directorio, seguido de un nombre de archivo y un final de línea. Esto hace que el primer grupo de captura sea el directorio principal de cada archivo.
  • La primera parte del nombre del archivo se descarta, excepto la terminación, para mantener el sufijo ordinal.

Elegí usar un enfoque más general que asumir que los archivos tenían 8 caracteres, pero la diferencia real es que no necesito la findconstrucción ni meter la $dirvariable en el entorno de expresiones regulares (posiblemente inseguro).

información relacionada