Achatando estrutura de pastas

Achatando estrutura de pastas

Eu tenho essa estrutura de pastas:

├── foo1
│   ├── bar1.txt
│   └── bar2.txt
├── foo2
│   ├── bar3.txt
│   └── bar4 with a space.txt
└── foo3
    └── qux1
        ├── bar5.txt
        └── bar6.txt

que eu gostaria de nivelar, com um sublinhado entre cada nível de pasta:

├── foo1_bar1.txt
├── foo1_bar2.txt
├── foo2_bar3.txt
├── foo2_bar4 with a space.txt
├── foo3_qux1.bar6.txt
└── foo3_qux1_bar5.txt

Procurei e não encontrei nenhuma solução que funcionasse, principalmente porque meu problema tem duas particularidades: pode haver mais de um nível de pasta dentro da raiz e também porque alguns arquivos podem ter espaços.

Alguma idéia de como fazer isso no bash? Obrigado!

Editar: Executando a resposta proposta de gleen jackman, recebo o seguinte:

insira a descrição da imagem aqui

Existem dois sublinhados para a pasta de primeiro nível. Alguma idéia de como evitar isso ou apenas renomeá-lo para que seja apenas um sublinhado? Obrigado.

Responder1

find */ -type f -exec bash -c 'file=${1#./}; echo mv "$file" "${file//\//_}"' _ '{}' \;

remova echose estiver satisfeito com o funcionamento. Não se preocupe, pois os comandos echo'ed não mostram aspas, o script irá lidar com arquivos com espaços corretamente.

Se você deseja remover os subdiretórios agora vazios:

find */ -depth -type d -exec echo rmdir '{}' \; 

Responder2

Usando a renomeação do Perl:

find . -depth -type f -exec rename 's@(?<!\.)/@_@g' -- {} \;

SAÍDA

$ find -type f
./foo2_bar4 whit a space.txt
./foo3_qux1_bar6.txt
./foo2_bar3.txt
./foo3_qux1_bar5.txt
./foo1_bar2.txt
./foo1_bar1.txt

OBSERVAÇÃO

  • Eu uso umolhar negativo para trás (?<!\.)não tocar no primeiro./
  • Eu mantenho os diretórios vazios, fique à vontade para:

    find . -depth -type d -exec rm {} \;

avisoExistem outras ferramentas com o mesmo nome que podem ou não fazer isso, então tome cuidado.

Se você executar o seguinte comando ( GNU)

$ file "$(readlink -f "$(type -p rename)")"

e você tem um resultado como

.../rename: Perl script, ASCII text executable

e não contendo:

ELF

então esta parece ser a ferramenta certa =)

Caso contrário, para torná-lo o padrão (geralmente já é o caso) em uma Debianderivada como Ubuntu:

$ sudo update-alternatives --set rename /path/to/rename

(substitua /path/to/renamepelo caminho do seu perl's renamecomando.


Se você não possui este comando, procure em seu gerenciador de pacotes para instalá-lo oufaça isso manualmente


Por último, mas não menos importante, esta ferramenta foi originalmente escrita por Larry Wall, o pai do Perl.

Responder3

compax...

pax -Xrwls '|/|_|g' */ "$PWD"

Isso criará um hardlink no diretório atual para todos os arquivos em seus diretórios filhos, substituído _por /. Você pode então inspecionar os resultados e remover todos os diretórios filhos com...

rm -rf */

...depois de verificar se os resultados estão do seu agrado.

Responder4

Você pode tentar com o comando abaixo.

$ find -type f -exec bash -c 'mv $0 $(echo $0|sed "s/\//_/2")' {} \;

O comando acima moverá os arquivos e o diretório permanecerá, que poderá ser removido posteriormente.

$ ls
foo1_bar1.txt  foo1_bar2.txt  foo2_bar3.txt  foo2_bar4.txt  foo3_bar5.txt  foo3_bar6.txt

informação relacionada