Achatando estruturas de pastas complexas com nomes de arquivos duplicados

2

Eu tenho uma pasta com uma estrutura de pastas complicada:

├── folder1
│   ├── 0001.jpg
│   └── 0002.jpg
├── folder2
│   ├── 0001.jpg
│   └── 0002.jpg
├── folder3
│    └── folder4
│         ├── 0001.jpg
│         └── 0002.jpg
└── folder5
     └── folder6
           └── folder7
                ├── 0001.jpg
                └── 0002.jpg   

Gostaria de achatar a estrutura de pastas, de modo que todos os arquivos residam no diretório pai com nomes exclusivos, como folder1_0001.jpg, folder1_0002.jpg ... folder5_folder6_folder7_0001.jpg etc.

Eu tentei usar o código sugerido em "Estruturando a estrutura de pastas"

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

O echo demonstra que está funcionando:

mv folder3/folder4/000098.jpg folder3_folder4_000098.jpg

Mas os arquivos de saída não são colocados no diretório pai. Eu pesquisei a unidade inteira e não consigo encontrar os arquivos de saída.

Eu também tentei "Achatar uma estrutura de pastas para um nome de arquivo no Bash "

$ find . -type f -name "*.jpg" | sed 'h;y/\//_/;H;g;s/\n/ /g;s/^/cp -v /' | sh

-v demonstra que está funcionando:

‘./folder3/folder4/000098.jpg’ -> ‘._folder3_folder4_000098.jpg’

No entanto, a saída cria arquivos ocultos no diretório pai, isso dificulta meu fluxo de trabalho. Eu sou capaz de ver esses arquivos ocultos no diretório pai usando ls -a

Eu também testei o código sugerido abaixo em Renomeando arquivos duplicados com o comando Flatten Folders "

find . -mindepth 2 -type f | xargs mv --backup=numbered -t . && find . -type d -empty -delete

Mas o comando sobrescreve arquivos com nomes de arquivo semelhantes.

Alguma sugestão sobre como achatar uma estrutura de pastas complicada sem sobrescrever arquivos com nomes semelhantes? As soluções atuais parecem funcionar apenas em estruturas de pastas com uma camada de profundidade.

Meu objetivo final é converter os nomes exclusivos em números sequenciais, conforme descrito em " Renomeando arquivos em uma pasta para números sequenciais "

 a=1
  for i in *.jpg; do
  new=$(printf "%04d.jpg" "$a") #04 pad to length of 4
  mv -- "$i" "$new"
  let a=a+1
 done
    
por Andrew Brown 07.01.2016 / 20:19

4 respostas

3

Não tenho ideia de por que a primeira solução da sua pergunta não funcionaria. Eu só posso supor que você esqueceu de remover o echo . Seja como for, aqui está outra abordagem que também deve fazer o que você precisa, supondo que esteja executando bash :

shopt -s globstar
for i in **/*jpg; do mv "$i" "${i//\//_}"; done

Explicação

  • O shopt -s globstar ativa o recurso globstar do bash, o que torna ** recursivamente igual a qualquer número de diretórios ou arquivos.
  • for i in **/*jpg; irá iterar todos os arquivos (ou diretórios) cujos nomes terminem em .jpg , salvando cada um como $i .
  • "${i//\//_}" é o nome do arquivo (ou diretório) atual com todas as instâncias de / substituídas por _ .

Se você também tiver diretórios com nomes terminados em .jpg e quiser ignorá-los, faça isso:

shopt -s globstar
for i in **/*jpg; do [ -f "$i" ] && echo mv "$i" "${i//\//_}"; done

E para todos os arquivos, independentemente da extensão:

shopt -s globstar
for i in **/*; do [ -f "$i" ] && echo mv "$i" "${i//\//_}"; done
    
por 08.01.2016 / 11:50
2

Se você tem o Perl rename (às vezes chamado de prename ), você pode fazer isso:

find folder* -type f -name '*.jpg' -exec rename 's!/!_!g' {} \;

Isso leva cada caminho de nome de arquivo e substitui todas as ocorrências de / por _ .

Se você realmente quiser renomear os arquivos para uma série de nomes de arquivos de quatro dígitos consecutivos, você poderá usar isso em seu conjunto de dados original. Ele funcionará somente onde o diretório e os nomes de arquivos contiverem alfanuméricos regulares (especificamente, ele falhará se houver espaço, pontuação de shell ou outro espaço em branco):

rename 's!.*!sprintf "%04d.jpg", ++$a!e' $(find folder* -type f -name '*.jpg' | sort)

Use rename -n ... para ver o que aconteceria com a alteração de qualquer coisa ou use rename -v ... para assistir enquanto ela é executada.

    
por 07.01.2016 / 00:44
1
pax -rws'|/|_|g' folder*/ .

... funcionará desde que não haja como sobrepor os nomes dos arquivos. Para fazer isso com mais segurança, use a opção -l link e espelhe a árvore em outro caminho e, em seguida, inspecione a nova árvore antes de remover a antiga.

    
por 07.01.2016 / 09:48
-2

Eu obtive sucesso com o seguinte script:

#!/bin/sh

for folder in $(ls $1)
do
  for file in $(ls ${folder})
  do
    mv ${folder}/${file} $1/${folder}_${file}
  done
  rmdir ${folder}
done
    
por 07.01.2016 / 09:42