Inverter estrutura de diretórios

1

Eu cometi um erro horrível em um cálculo muito demorado.

Uma parte da computação armazena arquivos de resultados em uma estrutura de diretórios da seguinte forma:

path/to/first/[A,B,C,D]/[1,2,3,4,5]/outfiles

E outro faz assim:

path/to/second/[1,2,3,4,5]/[A,B,C,D]/outfiles

Ou seja, quando a parte 1 do script armazena arquivos, ele cria um diretório para, digamos, A e, em seguida, armazena as iterações 1,2,3,4 e 5 como subdiretórios. Quando a parte 2 faz seus cálculos, ela cria um diretório para a iteração 1 e, em seguida, armazena a primeira iteração dos cálculos A, B, C e D em subdiretórios.

Gostaria de "inverter" a segunda estrutura de diretórios para ser como a primeira, pois executar novamente o script original com a correção de diretório demorará muito e meu código de pós-processamento que deveria funcionar para a parte 2 já será manipulado estrutura da parte 1.

Ou seja, path/to/second/1/A deve se tornar path/to/second/A/1 , contendo os arquivos que anteriormente eram 1/A . Existe uma maneira simples de conseguir isso?

Para complicar a tarefa de criar diretórios temporários, enquanto usei [A, B, C, D] e [1,2,3,4,5] no meu exemplo para clareza, os diretórios das duas hierarquias são apenas números e definitivamente tem colisões de nome (isto é, coisas como 10/10 existem).

    
por LinearZoetrope 19.05.2016 / 05:47

3 respostas

2

A questão é, na verdade, renomear todos os diretórios nomeados com um inteiro, por uma maiúscula com o índice correspondente (+1) do alfabeto e vice-versa:

1 -> A

enquanto, por exemplo,

C -> 3

Supondo que você não tenha mais de 26 pastas em um nível (número de letras no alfabeto), a questão não é essa complicada, mas precisamos levar em consideração algumas coisas:

  1. Precisamos renomear os diretórios de baixo para cima , já que a movimentação de diretórios dentro de diretórios renomeados entrará em colapso.
  2. Como você mencionou possíveis conflitos de nomes, precisamos renomear duas execuções :
    1. renomeia os diretórios, adicionando uma string única, sem sentido, para evitar confrontos de nomes
    2. remova a string depois que toda a renomeação ocorrer

Isso é exatamente o que o script abaixo faz:

O script

#!/usr/bin/env python3
import string
import shutil
import os
import sys

reorg = sys.argv[1]

chars = list(string.ascii_uppercase)
nums = [str(i+1) for i, c in enumerate(chars)]

tempstring = "_temp1234"

# first step: rename from bottom to top
for root, dirs, files in os.walk(reorg, topdown = False):
    for dr in dirs:
        tempname = None
        if dr in chars:
            tempname = str(chars.index(dr)+1)+tempstring
        elif dr in nums:
            tempname = chars[nums.index(dr)]+tempstring
        if tempname:
             print(dr, tempname)
             shutil.move(root+"/"+dr, root+"/"+tempname)

# second step: remove the temporary string
for root, dirs, files in os.walk(reorg, topdown = False):
    for dr in dirs:
        if tempstring in dr:
            shutil.move(root+"/"+dr, root+"/"+dr.replace(tempstring, ""))

Para usar

  1. Copie o script em um arquivo vazio, salve-o como reorg.py
  2. Execute-o com o diretório de destino como argumento:

    python3 /path/to/reorg.py /path/to/second
    

Como sempre, tente primeiro uma amostra.

    
por Jacob Vlijm 19.05.2016 / 11:16
0

Isso deve fazer o que você quer no bash:

#!/bin/bash
mkdir -p /path-to-second-new/{A,B,C,D}
for i in [1,2,3,4,5]
do 
    for j in [A,B,C,D]
    do
        cp -v /path-to-second/"$i"/"$j" /path-to-second-new/"$j"/"$i"
    done
done

Sua estrutura normal deve então estar em /path-to-second-new/ e sua estrutura inicial intocada em /path-to-second/ .

    
por Videonauth 19.05.2016 / 11:37
0

Eu estava enfrentando o mesmo problema recentemente em uma situação em que não era prático listar todas as pastas manualmente. Querendo usar um script bash, eu criei o seguinte:

for a in */; do
    for b in $a/*/; do
        dir=${b##*//}
        mkdir -p $dir$a
        mv $a$dir* $dir$a
    done
    rm -rf $a
done

Isso dinamicamente captura os nomes das pastas, cria a nova hierarquia, move todos os arquivos e remove as pastas antigas.

A extração da pasta de segundo nível usa um pouco de hack. Todos os nomes de diretório $a terminarão em / (por exemplo, folder1/ ). No segundo for-loop eu acrescento outra barra após $a (o primeiro / em $a/*/ ), então cada entrada $b parecerá com folder1//folder2/ . Essa barra dupla é ignorada pelo Unix, então eu posso filtrar o nome do diretório cortando tudo até e incluindo essa barra dupla com dir=${b##*//} .

    
por Energya 25.09.2017 / 15:16