Com Bash, como faço para encontrar todos os diretórios com dois diretórios e movê-los para uma estrutura de árvore copiada?

1

Digamos que eu tenha a seguinte estrutura em árvore de diretórios:

./Original
  ├── Dir1
  │   ├── Objects
  │   └── Textures
  ├── Dir2
  │   ├── SubDir1
  │   │   └── SubSubDir1
  │   │       ├── Objects
  │   │       └── Textures
  │   └── SubDir2
  │       ├── Objects
  │       └── Textures
  └── Dir3
      ├── Objects
      ├── SubDir1
      │   ├── Objects
      │   └── Textures
      └── Textures

E também tenho uma estrutura semelhante (na verdade, é uma cópia do Diretório original sem os diretórios Objetos e Texturas:

./Copy
  ├── Dir1
  ├── Dir2
  │   ├── SubDir1
  │   │   └── SubSubDir1
  │   └── SubDir2
  └── Dir3
      └── SubDir1

Como faço para mover todos os diretórios Objetos e Texturas e seus arquivos do original para a posição correspondente no Diretório de Cópia? Deve ficar assim quando terminar:

./Original
  ├── Dir1
  ├── Dir2
  │   ├── SubDir1
  │   │   └── SubSubDir1
  │   └── SubDir2
  └── Dir3
      └── SubDir1

./Copy
  ├── Dir1
  │   ├── Objects
  │   └── Textures
  ├── Dir2
  │   ├── SubDir1
  │   │   └── SubSubDir1
  │   │       ├── Objects
  │   │       └── Textures
  │   └── SubDir2
  │       ├── Objects
  │       └── Textures
  └── Dir3
      ├── Objects
      ├── SubDir1
      │   ├── Objects
      │   └── Textures
      └── Textures

Coisas para perceber:

  • Nem todos os diretórios no Diretório original possuem diretórios Objetos e Texturas
  • Os Diretórios Objetos e Texturas são movidos e não copiados
  • Além disso, os diretórios Original e Copy estão no mesmo diretório e é nesse local que o comando / função deve ser chamado

Por favor use este comando para construir a estrutura inicial:

mkdir -p Original/Dir1/Objects Original/Dir1/Textures Original/Dir2/SubDir1/SubSubDir1/Objects Original/Dir2/SubDir1/SubSubDir1/Textures Original/Dir2/SubDir2/Objects Original/Dir2/SubDir2/Textures Original/Dir3/Objects Original/Dir3/Textures Original/Dir3/SubDir1/Objects Original/Dir3/SubDir1/Textures
mkdir -p Copy/Dir1 Copy/Dir2/SubDir1/SubSubDir1 Copy/Dir2/SubDir2 Copy/Dir3/SubDir1
    
por kingcobra1986 05.10.2017 / 19:43

4 respostas

4

Esta é uma simulação. Depois de executá-lo e ter certeza de que tudo está correto, remova echo e execute-o novamente:

shopt -s globstar
for d in **/{Objects,Textures}; do
    echo mv "$d" "Copy/${d##Original/}"
done

Explicação:

  • Ativar a opção Bash "globstar" faz com que o glob **/ corresponda a zero ou mais subdiretórios.
  • O Bash expande **/{Objects,Textures} para **/Objects **/Textures .
  • ${d##Original/} significa "remover a string Original/ do início de $d .
por wjandrea 05.10.2017 / 21:06
2

Se você deseja atualizar as árvores de diretórios usando outro local, a melhor ferramenta é rsync , a segunda melhor possível, tar . Escrever um script de shell é muitas vezes um exagero:

rsync -aP --ignore-existing Original/ Copy

As opções:

  • -a informa rsync para reter propriedades, modos, etc.
  • -P imprime informações de progresso
  • --ignore-existing significa que os arquivos que já estão em Copy não serão tocados.
  • O trailing / após Original diz a rsync para copiar o conteúdo de Original para Copy , em vez de copiar Original em si.

Apague Original quando terminar, ou use a opção --remove-source-files files para ter rsync delete arquivos quando for copiá-los.

    
por muru 06.10.2017 / 12:27
1

Aqui está uma maneira de gerenciar diretórios sem subdiretórios .

Primeiro, ligue a globalização recursiva:

shopt -s globstar

Agora você pode globar recursivamente com ** . Você pode desativá-lo com shopt -u globstar , mas ele será desativado da próxima vez que você abrir um shell.

Agora, no diretório pai de ambos os Copy e Original :

for d in Original/**/; do $(ls -lAq "$d" | grep -q '^d') || echo mv -vn -- "$d" Copy"${d/Original/}"; done

Remova echo após o teste para mover realmente os diretórios (e seu conteúdo é claro - mv não tem um sinalizador -r )

Vamos tornar isso um pouco mais legível

shopt -s globstar
for d in Original/**/; do 
    $(ls -lAq "$d" | grep -q '^d') || 
    echo mv -vn -- "$d" Copy"${d/Original/}"
done

Espere, eu acabei de analisar a saída de ls ? Sim, eu fiz. Mas acho que está tudo bem (!) Já que acho que posso confiar na consistência da saída nesse caso. Independentemente dos caracteres que um nome de arquivo contém, a saída de ls -l no diretório em que o arquivo reside começará com uma cadeia que define seu tipo e permissões. Em ls -l , todas as listagens de diretório começam com d , por exemplo

drwxrwxr-x 26 zanna zanna 4096 Oct  5 19:57 playground

Mesmo novas linhas não estragam tudo isso, pois elas são exibidas como ? (mesmo depois da canalização) se adicionarmos -q .

$(ls -lAq "$d" | grep -q '^d') 

verifica se o diretório possui alguns subdiretórios. Em vez de coletar a saída de grep , coletamos o status de saída. Se o comando for bem sucedido, não fazemos nada, mas se falhar, nós mv do diretório (usando o || ou operador, o que significa que, se o comando antes de || falhar, faça o seguinte).

Usamos a manipulação de strings para remover Original , então os diretórios são copiados para os lugares certos em Copy .

Aqui está o resultado:

$ tree
.
├── Copy
│   ├── Dir1
│   │   ├── Objects
│   │   └── Textures
│   ├── Dir2
│   │   ├── SubDir1
│   │   │   └── SubSubDir1
│   │   │       ├── Objects
│   │   │       └── Textures
│   │   └── SubDir2
│   │       ├── Objects
│   │       └── Textures
│   └── Dir3
│       ├── Objects
│       ├── SubDir1
│       │   ├── Objects
│       │   └── Textures
│       └── Textures
└── Original
    ├── Dir1
    ├── Dir2
    │   ├── SubDir1
    │   │   └── SubSubDir1
    │   └── SubDir2
    └── Dir3
        └── SubDir1
    
por Zanna 05.10.2017 / 21:15
0

Veja um exemplo de como isso pode funcionar para você. Por favor, note que este script deve ser executado no mesmo nível com os diretórios original e copy e também que ele provavelmente precisa de adaptação às suas necessidades reais. Boa sorte.

#!/bin/bash

src="original" 
dst="./copy"

function findLocation {
    for i in 'find $src/ -type d -name ""'; do
        IFS='/' read -ra directories <<< "$i"
        dirNum=${#directories[@]}
        let "arrayNum=$dirNum-2"

        arrs=()

        for ((k=1 ; k<=$arrayNum; k++)); do
            arrs+=("${directories[$k]}")
        done

        echo "===============================++++++++++++++++"

        function join {
            local IFS=""
            shift
            echo "$*"
        }

        constructDst='join / ${arrs[@]}'
        destination="$dst/$constructDst/"

        if [ ! -d $destination ] ; then
            mkdir -p $destination
            echo "creating directory: $destination"
        fi

        if [ -d $i ]; then
            echo "Moving $i to $destination"
            mv $i -t $destination
        fi
    done
}

findLocation Textures 
findLocation Objects
    
por Alex Austin 05.10.2017 / 23:15