Как извлечь папку с определенным именем из рекурсивного каталога, удалить остальные?

10

У меня есть такой вид дерева каталогов, который получается при распаковке zip-файла:

x -> y -> z -> run -> ФАЙЛЫ И КАТАЛОГИ ЗДЕСЬ

Таким образом, существует 4 каталога, 3 из которых не содержат файлов (x, y, z) и содержат только 1 подкаталог, и есть интересующий меня каталог с именем « run ».

Я хочу переместить сам каталог «run» (включая все внутри) в «корневую» папку, где я распакован (то есть, где находится «x», но не внутри «x»).

Допущения: существует папка с именем «run», но я не знаю, сколько каталогов мне понадобится для «cd», чтобы добраться до нее (может быть 3 (x, y, z), может быть 10 или более). также неизвестны и не должны быть x, y, z и т. д.).

Как я могу сделать это? Я перепробовал много вариантов этого вопроса, но все они провалились.

Idos
источник
1
Боюсь, картина не очень четкая, нет. Пожалуйста, не размещайте скриншоты текста . Вместо этого вставьте текст прямо в ваш вопрос и используйте инструменты форматирования . Я даже не могу прочитать название каталога на вашей картинке. Все, что я вижу, это тусклое синее пятно.
Terdon

Ответы:

14

что о

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

где

  • / path / to / X - ваш целевой каталог
  • Вы начинаете с этого же места.
  • затем используйте другой ответ, чтобы удалить пустые каталоги.

(на боковой ноте есть --junk-pathsопция в zip, либо при архивировании, либо при распаковке)

Archemar
источник
7

Я бы сделал это bash, используя globstar. Как объяснено в 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.

Итак, чтобы переместить каталог в каталог runверхнего уровня x, а затем удалить остальные, вы можете сделать:

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

Команда shoptвключает globstarопцию. Команда mv x/**/run/ x/переместит любые названные подкаталоги run(обратите внимание, что это работает только при наличии только одного runкаталога) xи findудалит все пустые каталоги.

Если хотите, вы можете сделать все это в оболочке с расширенным глобализацией, но я предпочитаю, чтобы сеть безопасности find -emptyбыла уверена, что непустые каталоги не будут удалены. Если вас это не волнует, вы можете использовать:

shopt -s globstar; shopt -s extglob; mv x/**/run/ x/ && rm -rf x/!(run)
Тердон
источник
6

Определенно более многословный, но выполняющий работу за один шаг:

Предполагая, что у вас установлен Python

#!/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]))

Как пользоваться

  1. Скопируйте скрипт в пустой файл, сохраните его как get_folder.py
  2. Запустите его с корневым каталогом (связываясь с вашими разархивированными файлами) и именем папки, которую нужно «поднять» в качестве аргументов:

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

И это сделано:

введите описание изображения здесь

введите описание изображения здесь

Якоб Влейм
источник
Это очень интересное решение, но я предпочитаю не использовать скрипт Python по разным причинам. Спасибо, что!
Idos
Нет проблем. Может быть, это кому-нибудь пригодится. Любопытно, почему, хотя? Я уверен, что многие приложения уже используют Python.
Джейкоб Влейм
Главным образом, поскольку размещение файла .py в любом месте будет проблематичным, я должен предположить, что он находится в одном и том же месте для каждой машины Linux, на которой будет выполняться мой сценарий (и мой сценарий запускается на многих платформах).
Idos
@ Идос просто любопытно, какие платформы? Python довольно широко распространен. Я не думаю, что он установлен на Mac OS X по умолчанию, но в большинстве дистрибутивов Linux он есть
Сергей Колодяжный,
4

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");

Это работает просто: find()подпрограмма рекурсивно обходит заданное дерево каталогов, находит каталог с именем runи помещает его в массив желаемых имен файлов. В этом случае мы предполагаем, что в списке должен быть только один файл, поэтому после завершения команды мы используем модуль dirmove()из File::Copy::Recursiveмодуля и перемещаем его в текущий рабочий каталог, из которого был вызван скрипт. Таким образом, в вашем случае вы бы назвали его из родительского каталога в x.

Исходное дерево каталогов:

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

Результат:

$ ~/find_dir.pl .  
$ tree 
.
├── levelone
│   └── leveltwo
│       └── levelthree
└── run
    ├── file1
    ├── file2
    └── file3
Сергей Колодяжный
источник