Mover arquivos de vários diretórios para vários diretórios com layout semelhante

1

Eu tenho um diretório com o layout a seguir (o layout em Directory 1 é repetido em todos os outros Directory <num> ):

Parent directory
   Directory 1
      some directory
         another directory
            <many files>
   Directory 2
       ︙
   Directory 3
   Directory 4

Gostaria de renomear os arquivos prefixando-os com Directory <num> e movendo-os 3 diretórios para que fiquem abaixo do Parent directory e excluam os diretórios originais (agora vazios):

Parent directory
   Directory 1_<many files>
   Directory 2
       ︙
   Directory 3
   Directory 4

Como eu poderia fazer isso?

O seguinte de uma pergunta semelhante

find . -mindepth 2 -name '*.jpg' -exec rename -n 's!/([^/]+)$!_$1!' {} +

renomeia os arquivos para o primeiro diretório pai:

Parent directory
   Directory 1
      another directory_<many files>
   Directory 2
       ︙
    
por user10853 28.05.2016 / 02:06

1 resposta

2

Primeiro de tudo, Não consigo reproduzir os resultados que você afirma para o comando mostrado. Eu tenho os arquivos sendo renomeados para another directory_file1.jpg , another directory_file2.jpg , etc. , mas ainda sob os diretórios some directory .

Em segundo lugar, devido à profundidade da sua estrutura de diretórios, você deve estar usando -mindepth 4 em vez de 2 . Em terceiro lugar, eu recomendo strongmente que você use -type f . Enquanto você estiver usando -name '*.jpg' , você provavelmente não encontrará nenhum diretório. Mas daqui a seis a oito semanas, você verá isso e pensar "Quero que isso se aplique a todos os meus arquivos - Eu não preciso dizer -name '*.jpg' , e você vai tirar. E então, se você não tiver -type f , o comando find pode começar a localizar diretórios e renomeá-los. E modificando uma árvore de diretórios enquanto você a escaneia é uma receita para o desastre (como o proverbial "pilotar o avião enquanto ainda o estamos construindo").

Em quarto lugar, o comando rename para mover um arquivo em três níveis e prefixar seu nome com Directory <num>_ is

rename     -n     's!/[^/]+/[^/]+/([^/]+)$!_$1!'
        (optionally)

porque /[^/]+ representa um nível de diretório então eu adicionei mais duas cópias disso.

Aviso: Isto irá, como eu disse, mover um arquivo em três níveis. Se você tem algum arquivo mais profundo na árvore de diretórios do que isso, eles não serão renomeados para o nível superior; eles podem ser renomeados para algo como Directory 3/some directory_file3.jpg .

Mas isso é fácil de corrigir. Para mover um arquivo para o nível superior de qualquer profundidade em , e prefixar seu nome com Directory <num>_ , é só usar

s!(\./[^/]+)/.*/([^/]+)$/$1_$2/!

TL; DR

Então,

O comando final é

find . -mindepth 4 -type f -exec rename -n 's!/[^/]+/[^/]+/([^/]+)$!_$1!' {} +

Adicione -name '*.jpg' se você quiser. Exclua -n quando a saída de rastreamento mostrar que está fazendo a coisa certa.

Tenha em atenção que isto tem potencial para ter colisões de nomes de ficheiros. Se você tiver arquivos

Directory 1/some directory/another directory/sunrise.jpg

e

Directory 1/some directory/another directory/mountains/sunrise.jpg

este comando tentará renomeá-los para Directory 1_sunrise.jpg . Felizmente, o programa rename parece ser inteligente / amigável o suficiente não fazer mal neste caso. O primeiro desses arquivos que ele verá (provavelmente) será renomeado; os outros serão deixados onde estão (e você será notificado). (Você pode usar -f ou --force para forçar a substituição de arquivos existentes.) Mas lembre-se de que alguns outros programas (por exemplo, mv ) tem ações padrão menos amigáveis.

Para a pergunta atualizada ("Como posso incluir todos os nomes de diretório nos nomes dos arquivos?"): isso é um pouco mais complicado. Vou assumir explicitamente que estamos pesquisando . , então todos os nomes de caminho começarão com ./ . E eu descobri que o argumento perlexpr para rename pode realmente conter vários comandos de modificação de string. Então podemos mover todos os arquivos para o nível superior e prefixar seus nomes com todos os nomes de diretório no caminho com

s!^\./!!;s!/!_!g

Isso também tem a possibilidade de colisões de nomes de arquivos.

Directory 1/abc/def_ghi/sunrise.jpg

e

Directory 1/abc_def/ghi/sunrise.jpg

(potencialmente) ambos serão renomeados para Directory 1_abc_def_ghi_sunrise.jpg .

Aviso: Eu testei isso, mas não completamente. Eu não garanto que isso funcionará perfeitamente. Você deve fazer um backup completo antes de tentar os comandos acima.

    
por 28.05.2016 / 09:23