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

Я понимаю, что название является неопределенным, лучше всего объясняется примером.
У меня есть такое дерево каталогов, которое получается при распаковке zip-файла:

  

x -> y -> z -> запустить -> ФАЙЛЫ И ДИРЕКТОРИИ ЗДЕСЬ

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

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

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

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

10 голосов | спросил Idos 5 MaramSun, 05 Mar 2017 11:58:49 +03002017-03-05T11:58:49+03:0011 2017, 11:58:49

4 ответа


13

как насчет

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

, где

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

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

ответил Archemar 5 MarpmSun, 05 Mar 2017 12:12:07 +03002017-03-05T12:12:07+03:0012 2017, 12:12:07
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)
ответил terdon 5 MarpmSun, 05 Mar 2017 17:09:17 +03002017-03-05T17:09:17+03:0005 2017, 17:09:17
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
    

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

 введите описание изображения здесь>> </a> </p>

<p> <a href= введите описание изображения здесь>> </a> </p></body></html>

ответил Jacob Vlijm 5 MarpmSun, 05 Mar 2017 13:51:32 +03002017-03-05T13:51:32+03:0001 2017, 13:51:32
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
ответил Sergiy Kolodyazhnyy 6 MaramMon, 06 Mar 2017 02:19:49 +03002017-03-06T02:19:49+03:0002 2017, 02:19:49

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132