Como mover todos os arquivos de vários diretórios para seus diretórios pais usando bash

Como mover todos os arquivos de vários diretórios para seus diretórios pais usando bash

Eu tenho a seguinte estrutura de arquivos:

  • /home/dados/C01/dir_wwe_346/arquivo1.txt pic.jpg random.sh
  • /home/dados/C02/dir_wwe_644/arquivo1.txt pic.jpg random.sh
  • /home/dados/C03/dir_wwe_324/arquivo1.txt pic.jpg random.sh

Eu quero que eles sejam assim:

  • home/data/C01/file1.txt pic.jpg random.sh
  • home/data/C02/file1.txt pic.jpg random.sh
  • home/data/C03/file1.txt pic.jpg random.sh

Basicamente, é mover vários arquivos para um diretório acima. Tentei este script sem sucesso:

#!/bin/bash for i in */ do cd i/*/ mv * ../ done


Depois de postar isso (mas antes de ler a resposta do grawity abaixo), percebi que não usei a expansão de variável adequada e executei isto:

#!/bin/bash for i in */ do cd ${i}*wwe* mv * ../ done

O script está movendo todos os subdiretórios para a pasta de dados, então estou terminando com isto:

  • /lar/C01/dir_wwe_346/arquivo1.txt pic.jpg random.sh
  • /lar/C02/dir_wwe_644/arquivo1.txt pic.jpg random.sh
  • /lar/C03/dir_wwe_324/arquivo1.txt pic.jpg random.sh

    O que estou fazendo de errado?


PS. Editei a postagem para que revele o processo pelo qual passei e para que as respostas façam mais sentido para os recém-chegados que possam se beneficiar com elas. Obrigado grawity, aprendi algo novo. Comecei a aprender bash há uma semana e sinto que estou progredindo.

Responder1

  1. As variáveis ​​só são reconhecidas e expandidas com o $prefixo. Se o loop definir uma variável 'i', você precisará usar$isempre que você quiser seu valor:

    for i in */; do
        cd $i/*/
    
  2. O "diretório atual" abrange todo o processo e não redefine automaticamente cada iteração do loop. Você precisa retornar manualmente ao diretório pai posteriormente:

    cd $i/*/; mv * ../; cd ../../
    

    ou use um "subshell" para definir o escopo da alteração do diretório:

    (cd $i/*/; mv * ../)
    
  3. Você não está fazendo nenhuma verificação de erros. Se cdalguma vez falhar, o subsequente mvpoderá fazer coisas desagradáveis. Junte os comandos usando &&ou faça a verificação oposta e use || exit(ou || break), o que parecer melhor:

    for i in */; do
        cd $i/*/ && {
            mv * ../;
            cd ../../
        }
    done
    
    for i in */; do
        cd $i/*/ || exit
        mv * ../
        cd ../../
    done
    
    for i in */; do
        (cd $i/*/ && mv * ../)
    done
    
  4. Melhoria: você pode mover o curinga do subdiretório para mv, permitindo que funcione mesmo no caso de haver vários subdiretórios:

    cd $i/ || exit
    mv */* .
    cd ../
    
  5. Melhoria: você poderia fazer isso sem precisar cdde nada:

    mv $i/*/* $i/
    

informação relacionada