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.


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)


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)

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


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.