mover arquivos para um nível acima, acrescentando o nome da pasta ao nome do arquivo?

mover arquivos para um nível acima, acrescentando o nome da pasta ao nome do arquivo?

Ambiente de teste:

  • crie diretórios de 0para 9e preencha-os com arquivos de aparaz
    $ mkdir {0..9} && touch {0..9}/{a..z}
    
  • Resultado de find:
    $ find -type f
    ./0/a
    ./0/b
    
    ...
    
    ./9/y
    ./9/z
    

Como posso transformar a saída para que fique assim:

./0a    
./0b

...

./9y
./9z

Responder1

Com renameo comando independente do Perl:

rename -n 's|/||' */*

Se tudo parecer bem, remova -ne remova os diretórios vazios restantes.

rmdir {0..9}

Responder2

Com ferramentas POSIX,

find . -type f -exec sh -c 'for f; do dirn="${f%/*}"; mv -- "$f" "$dirn${f##*/}"; done' sh {} +

findinvoca um shell e executa o loop for para cada arquivo.

  • dirn="${f%/*}"obtém o nome do diretório pai excluindo tudo o que vem depois (e incluindo) a última barra no nome do arquivo.

  • ${f##*/}obtém o nome do arquivo sem o caminho, excluindo tudo o que está antes (e incluindo) a última barra no nome do arquivo.

Essas duas construções de shell fazem o mesmo quedirnameebasename, então uma forma equivalente do comando é

find . -type f -exec sh -c 'for f; do mv -- "$f" "$(dirname "$f")$(basename "$f")"; done' sh {} +

, embora este deva ser mais lento, pois precisa gerar dois processos extras para cada arquivo.

Se você não precisar descer para mais de um diretório, como mostra seu exemplo, um simples loop de shell fará isso:

for f in */*; do dirn="${f%/*}"; echo mv -- "$f" "$dirn${f##*/}"; done

informação relacionada