Làm thế nào để trích xuất một thư mục có tên cụ thể từ một thư mục đệ quy, xóa các thư mục khác?


10

Tôi có loại cây thư mục này thu được từ việc giải nén tệp zip:

x -> y -> z -> chạy -> PHIM VÀ GIÁM ĐỐC TẠI ĐÂY

Vì vậy, có 4 thư mục, 3 trong số đó là các tệp trống (x, y, z) và chỉ chứa 1 thư mục con, và có thư mục tôi quan tâm, được đặt tên là " chạy ".

Tôi muốn tự di chuyển thư mục "chạy" (bao gồm mọi thứ bên trong) đến vị trí "gốc" nơi tôi đã giải nén (tức là "x", nhưng không nằm trong "x").

Giả định: Tồn tại một thư mục có tên "run", nhưng tôi không biết mình sẽ phải "cd" bao nhiêu thư mục để đến đó (có thể là 3 (x, y, z), có thể là 10 hoặc nhiều hơn. cũng chưa biết và không phải là x, y, z, v.v.).

Làm thế nào tôi có thể thực hiện điều này? Tôi đã thử nhiều biến thể của câu hỏi này nhưng tất cả đều thất bại.


1
Tôi sợ hình ảnh không rõ lắm, không. Xin vui lòng không đăng ảnh chụp màn hình của văn bản . Thay vào đó, dán văn bản trực tiếp vào câu hỏi của bạn và sử dụng các công cụ định dạng . Tôi thậm chí không thể đọc tên thư mục trong ảnh của bạn. Tất cả những gì tôi thấy là một vệt mờ màu xanh.
terdon

Câu trả lời:


14

Thế còn

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

Ở đâu

  • / path / to / X là thư mục đích của bạn
  • bạn bắt đầu từ nơi này
  • sau đó sử dụng câu trả lời khác để loại bỏ các thư mục trống.

(trên một ghi chú bên cạnh có một --junk-pathstùy chọn trong zip, khi nén hoặc giải nén)


7

Tôi sẽ làm điều này trong bash, sử dụng globstar. Như đã giải thích trong 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.

Vì vậy, để di chuyển thư mục runđến thư mục cấp cao nhất x, sau đó xóa phần còn lại, bạn có thể làm:

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

Các shoptlệnh cho phép globstartùy chọn. Các mv x/**/run/ x/sẽ di chuyển bất kỳ thư mục con có tên run(lưu ý rằng điều này chỉ hoạt động nếu chỉ có một runthư mục) để xfindsẽ xóa bất kỳ thư mục rỗng.

Bạn có thể thực hiện toàn bộ nội dung trong trình bao với mở rộng toàn cầu, nếu bạn thích, nhưng tôi thích mạng lưới an toàn hơn find -emptyđể đảm bảo không có thư mục không trống nào bị xóa. Nếu bạn không quan tâm đến điều đó, bạn có thể sử dụng:

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

6

Chắc chắn dài dòng hơn, nhưng thực hiện công việc trong một bước:

Giả sử bạn đã cài đặt 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]))

Cách sử dụng

  1. Sao chép tập lệnh vào một tập tin trống, lưu nó dưới dạng get_folder.py
  2. Chạy nó với thư mục gốc (chống lại nội dung được giải nén của bạn) và tên của thư mục để "nâng" làm đối số:

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

Và nó đã được thực hiện:

nhập mô tả hình ảnh ở đây

nhập mô tả hình ảnh ở đây


Đây là một giải pháp rất thú vị nhưng tôi không thích sử dụng bất kỳ kịch bản python nào vì nhiều lý do. Cảm ơn tho!
Idos

Không vấn đề gì. Có lẽ nó được sử dụng cho bất cứ ai khác. Tò mò vì sao? Tôi khá chắc chắn nhiều ứng dụng đã sử dụng python.
Jacob Vlijm

Chủ yếu vì việc đặt tệp .py ở bất cứ đâu sẽ gặp vấn đề vì tôi phải giả sử nó ở cùng một vị trí cho mọi máy linux sẽ chạy tập lệnh của tôi (và tập lệnh của tôi chạy trên nhiều nền tảng).
Idos

@Idos chỉ tò mò, nền tảng nào? Python khá phổ biến. Tôi không nghĩ rằng nó được cài đặt trên Mac OS X theo mặc định, nhưng hầu hết các bản phân phối Linux đều có nó
Sergiy Kolodyazhnyy

4

Giải pháp 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");

Cách thức hoạt động này rất đơn giản: find()chương trình con sẽ duyệt qua cây thư mục đã cho theo cách đệ quy, tìm thư mục có tên runvà đẩy nó vào mảng tên tệp mong muốn. Trong trường hợp này, chúng tôi giả sử chỉ có một tệp trong danh sách, do đó, khi lệnh hoàn thành, chúng tôi sử dụng dirmove()từ File::Copy::Recursivemô-đun và di chuyển nó đến thư mục làm việc hiện tại từ đó tập lệnh được gọi. Vì vậy, trong trường hợp của bạn, bạn sẽ gọi nó từ thư mục cha đến x.

Cây thư mục gốc:

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

Kết quả:

$ ~/find_dir.pl .  
$ tree 
.
├── levelone
│   └── leveltwo
│       └── levelthree
└── run
    ├── file1
    ├── file2
    └── file3
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.