Script de shell para renomear vários arquivos do nome das pastas pai

Script de shell para renomear vários arquivos do nome das pastas pai

Eu tenho uma estrutura de arquivos assim:

  • 00000010
    • 000000001.arquivo1
    • 000000001.arquivo2
  • 00000020
    • 00000003.arquivo1
    • 00000003.arquivo2
    • 00000003.arquivo3
  • ...

Portanto, existem pastas com nomes de 8 dígitos contendo um ou mais arquivos com nomes começando com números de 8 dígitos. Mas esses nomes de arquivos estão – digamos – fora de sincronia. Então agora tento renomeá-los recursivamente no bash para arquivar:

  • 00000010
    • 000000010.arquivo1
    • 000000010.arquivo2
  • 00000020
    • 00000020.arquivo1
    • 00000020.arquivo2
    • 00000020.arquivo3
  • ...

Meu script se parece com:

#! /bin/bash

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

Mas isso não está funcionando e dá erros como

O símbolo global "$dir" requer um nome de pacote explícito na (eval 1) linha 1.

Como eu poderia escrever para renomear os arquivos de acordo com os nomes das pastas?

Obrigado pela ajuda!

Responder1

Como aprendi em outra resposta, que tenho que usar

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

Caso alguém tenha o mesmo problema...

Responder2

Eu realmente não gosto da resposta onde $direstá interpolado no padrão. Isso poderia levar a resultados inesperados se o diretório contivesse, por exemplo, um caractere que fosse interpretado como um token regexp especial.

Prefiro combinar os arquivos diretamente no padrão, eliminando a necessidade de fazer um loop nos diretórios e usar apenas um glob normal.

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

onde o glob atinge os arquivos individuais dentro dos diretórios (pode até ser especificado como base_directory/*/*.file*, ou similar, mas isso não deve importar aqui).

Observe que este é o comando completo, sem necessidade de findconstrução.

  • Eu uso #como separador em vez do "normal" /para evitar ter que escapar disso nos padrões.
  • Eu capturo o grupo (ganancioso) de "não é um separador de diretório", seguido por um separador de diretório, seguido por um nome de arquivo e um final de linha. Isso faz com que o primeiro grupo de captura seja o diretório pai de cada arquivo.
  • A primeira parte do nome do arquivo é descartada, exceto a finalização para manter o sufixo ordinal.

Optei por usar uma abordagem mais geral do que presumir que os arquivos tinham 8 caracteres, mas a verdadeira diferença é que não preciso da findconstrução nem de amontoar a $dirvariável no ambiente regexp (possivelmente inseguro).

informação relacionada