Mover e renomear arquivos com base no diretório de seus pais

1

Eu tenho uma coleção de diretórios que todos contêm um arquivo específico que é nomeado o mesmo em todos os diretórios.

dir1/dirA/file.txt
dir1/dirB/file.txt
dir1/dirC/file.txt
....
dir4/dirX/file.txt
dir4/dirY/file.txt
dir4/dirZ/file.txt

Eu quero copiar esses arquivos em outro diretório, de forma que o nome de cada arquivo seja o nome do diretório pai:

all_files/
    dirA.txt
    dirB.txt
    dirC.txt
    ....
    dirX.txt
    dirY.txt
    dirZ.txt

Embora eu entenda que esses exemplos podem causar sobreposição, isso não é um problema para mim - sei que todos os diretórios de destino têm nomes exclusivos.

Estou usando o bash no OS X. Tentei fazer várias coisas como essa (consulte aqui e aqui ). Meu pensamento seria dividir a corda nas barras, pegar a segunda até a última e usá-la, mas não consegui fazê-la funcionar (com base em isto e outros):

for name in 'ls */*/file'
    directory=${DIRS[${#DIRS[@]} - 2]}
    mv name ../all_files/${directory}.txt
done

No entanto, não consegui fazê-lo funcionar.

    
por dantiston 11.09.2014 / 01:44

2 respostas

1

Eu pensei um pouco sobre isso e descobri duas soluções. O primeiro usa basename e dirname:

for name in */*/file
    do cp $name ../all_files/$(basename -- "$(dirname -- "$name")")
done

Este usa a divisão de strings (como eu queria fazer originalmente)

for name in */*/choices
    do parts=(${name//\// })
    directory=${parts[${#parts[@]} - 2]}
    cp $name all_files/${directory}.txt
done

Espero que isso ajude alguém!

    
por 11.09.2014 / 01:44
2
for name in ./*/*/file.txt
do
    mv "$name" "../all_files/$(basename -- "$(dirname -- "$name")").txt"
done

Alguns comentários:

  • Nunca faça isso ou algo assim:

    for name in 'ls */*/file'
    

    Se os nomes dos arquivos tiverem espaços ou outros caracteres difíceis, os itens acima falharão. Em vez disso, use:

    for name in ./*/*/file
    

    O shell manipulará o acima corretamente, não importando o quão estranho seja o nome do arquivo.

  • Isso sofre de vários problemas:

    mv name ../all_files/${directory}.txt
    

    Mais importante, isso moverá o arquivo literalmente denominado name . Você deseja, em vez disso, mover o arquivo ao qual a variável name se refere. Para isso, use "$name" em vez de name . Observe o uso de aspas duplas aqui. Isso protege o nome da divisão de palavras para que isso funcione mesmo se o nome do arquivo tiver espaços ou outros caracteres difíceis.

    Da mesma forma, o local de destino deve ter aspas duplas em torno dele.

por 11.09.2014 / 01:51