Como extrair uma pasta nomeada especificamente de um diretório recursivo, excluir as outras?

10

Eu tenho esse tipo de árvore de diretório que é obtida ao descompactar um arquivo zip:

x -> y -> z -> run -> ARQUIVOS E DIRETÓRIOS AQUI

Portanto, existem 4 diretórios, 3 dos quais estão vazios de arquivos (x, y, z) e contêm apenas 1 subdiretório, e existe o diretório no qual estou interessado, chamado " run ".

Eu quero mover o diretório "run" (incluindo tudo dentro) para o local "raiz" onde descompactei (ou seja, onde "x" está, mas não dentro de "x").

Pressupostos: Não existe uma pasta chamada "run", mas eu não sei quantos diretórios terei de "cd" para chegar a ela (poderia ser de 3 (x, y, z), poderia ser 10 ou mais dos nomes. também são desconhecidos e não precisam ser x, y, z etc).

Como posso fazer isso? Tentei muitas variações dessa questão, mas todas falharam.

Idos
fonte
1
Receio que a imagem não esteja muito clara, não. Por favor, não poste capturas de tela de texto . Em vez disso, cole o texto diretamente na sua pergunta e use as ferramentas de formatação . Não consigo nem ler o nome do diretório na sua foto. Tudo o que vejo é um borrão azul escuro.
terdon

Respostas:

14

A respeito

  find . -type d -name run -exec mv {} /path/to/X \;

Onde

  • / path / to / X é o diretório de destino
  • você começa deste mesmo lugar.
  • depois use outra resposta para remover diretórios vazios.

(em uma nota lateral, há uma --junk-pathsopção no zip, ao compactar ou descompactar)

Archemar
fonte
7

Eu faria isso bashusando globstar. Como explicado em man bash:

globstar
      If set, the pattern ** used in a pathname expansion con‐
      text will match all files and zero or  more  directories
      and  subdirectories.  If the pattern is followed by a /,
      only directories and subdirectories match.

Portanto, para mover o diretório runpara o diretório de nível superior xe excluir o restante, você pode:

shopt -s globstar; mv x/**/run/ x/  && find x/ -type d -empty -delete

O shoptcomando ativa a globstaropção. Ele mv x/**/run/ x/moverá todos os subdiretórios nomeados run(observe que isso só funciona se houver apenas um rundiretório) xe findexcluirá os diretórios vazios.

Você pode fazer a coisa toda no shell com globbing estendido, se quiser, mas eu prefiro a rede de segurança find -emptypara garantir que nenhum diretório não vazio seja excluído. Se você não se importa com isso, pode usar:

shopt -s globstar; shopt -s extglob; mv x/**/run/ x/ && rm -rf x/!(run)
terdon
fonte
6

Definitivamente mais detalhado, mas fazendo o trabalho em uma etapa:

Supondo que você tenha python instalado

#!/usr/bin/env python3
import shutil
import os
import sys

dr = sys.argv[1]

for root, dirs, files in os.walk(dr):
    # find your folder "run"
    for pth in [d for d in dirs if d == sys.argv[2]]:
        # move the folder to the root directory
        shutil.move(os.path.join(root, pth), os.path.join(dr, pth))
        # remove the folder (top of the tree) from the directory
        shutil.rmtree(os.path.join(dr, root.replace(dr, "").split("/")[1]))

Como usar

  1. Copie o script em um arquivo vazio, salve-o como get_folder.py
  2. Execute-o com o diretório raiz (contendo seus itens descompactados) e o nome da pasta para "levantar" como argumentos:

    python3 /full/path/to/get_folder.py /full/path/to/folder_containing_unzipped_dir run
    

E está feito:

insira a descrição da imagem aqui

insira a descrição da imagem aqui

Jacob Vlijm
fonte
Esta é uma solução muito interessante, mas prefiro não usar nenhum script python por vários motivos. Obrigado tho!
Idos
Sem problemas. Talvez seja útil para qualquer outra pessoa. Curioso para quê? Tenho certeza de que muitos aplicativos já usam python.
23475 Jacob Vlijm # 03
Principalmente porque colocar o arquivo .py em qualquer lugar será problemático, pois devo assumir que ele está no mesmo lugar para todas as máquinas Linux que executam meu script (e meu script é executado em várias plataformas).
Idos
@ Idos apenas curioso, quais plataformas? Python é bastante difundido. Eu não acho que ele está instalado no Mac OS X por padrão, mas a maioria das distribuições Linux tem isso
Sergiy Kolodyazhnyy
4

Solução Perl

#!/usr/bin/env perl
use strict;
use warnings;
use File::Find;
use File::Copy::Recursive qw(dirmove);

my @wanted;
find(sub{ -d $_ && $_ eq "run" && push @wanted,$File::Find::name}, $ARGV[0]);
dirmove("$wanted[0]","./run");

A maneira como isso funciona é simples: a find()sub - rotina percorrerá a árvore de diretórios de forma recursiva, encontrará o diretório cujo nome é rune o empurrará para uma variedade de nomes de arquivos desejados. Neste caso, assume-se que deve haver apenas um arquivo na lista, assim, uma vez conclusão do comando, usamos dirmove()a partir File::Copy::Recursivedo módulo, e movê-lo para o diretório de trabalho atual a partir do qual script foi chamado. Assim, no seu caso, você o chamaria do diretório pai para x.

Árvore de diretórios original:

$ tree                                                                                                                   
.
└── levelone
    └── leveltwo
        └── levelthree
            └── run
                ├── file1
                ├── file2
                └── file3

Resultado:

$ ~/find_dir.pl .  
$ tree 
.
├── levelone
│   └── leveltwo
│       └── levelthree
└── run
    ├── file1
    ├── file2
    └── file3
Sergiy Kolodyazhnyy
fonte