วิธีการแตกโฟลเดอร์ที่มีชื่อเฉพาะจากไดเรกทอรีแบบเรียกซ้ำให้ลบโฟลเดอร์อื่น


10

ฉันมีไดเรกทอรีต้นไม้ชนิดนี้ที่ได้จากการขยายไฟล์ zip:

x -> y -> z -> run -> ไฟล์และคำสั่งที่นี่

ดังนั้นจึงมี 4 ไดเรกทอรี 3 คนในนั้นเป็นไฟล์ว่างเปล่า (x, y, z) และมีเพียง 1 ไดเรกทอรีย่อยและมีไดเรกทอรีที่ฉันสนใจชื่อ " run "

ฉันต้องการย้ายไดเรกทอรี "เรียกใช้" ตัวเอง (รวมถึงทุกอย่างภายใน) ไปยังตำแหน่ง "รูท" ที่ฉันคลายซิป (เช่นที่ "x" อยู่ แต่ไม่ใช่ภายใน "x")

สมมติฐาน: มีอยู่โฟลเดอร์ชื่อ "รัน" แต่ผมไม่ทราบว่าหลายไดเรกทอรีผมจะต้อง "ซีดี" จะได้รับไป (อาจจะ 3 (x, y, z) อาจจะเป็น 10 หรือมากกว่าโดยรายชื่อ. ไม่เป็นที่รู้จักและไม่จำเป็นต้องเป็น x, y, z เป็นต้น)

ฉันจะทำสิ่งนี้ได้อย่างไร ฉันลองคำถามนี้หลายรูปแบบแต่พวกเขาทั้งหมดล้มเหลว


1
ฉันเกรงว่าภาพจะไม่ชัดเจนไม่ กรุณาอย่าโพสต์ภาพหน้าจอของข้อความ แต่วางข้อความโดยตรงในคำถามของคุณและใช้เครื่องมือในการจัดรูปแบบ ฉันไม่สามารถอ่านชื่อไดเรกทอรีในรูปภาพของคุณได้ สิ่งที่ฉันเห็นคือพร่ามัวสีน้ำเงิน
terdon

คำตอบ:


14

เกี่ยวกับอะไร

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

ที่ไหน

  • / path / to / X เป็นไดเรกทอรีปลายทางของคุณ
  • คุณเริ่มต้นจากที่เดียวกัน
  • จากนั้นใช้คำตอบอื่น ๆ เพื่อลบไดเรกทอรีว่าง

(ในบันทึกด้านข้างมี--junk-pathsตัวเลือกในการซิปทั้งเมื่อซิปหรือคลายซิป)


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

verbose แน่นอนมากขึ้น แต่การทำงานในขั้นตอนเดียว:

สมมติว่าคุณติดตั้งงูหลามไว้

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

และจะทำ:

ป้อนคำอธิบายรูปภาพที่นี่

ป้อนคำอธิบายรูปภาพที่นี่


นี่เป็นวิธีแก้ปัญหาที่น่าสนใจมาก แต่ฉันไม่ต้องการใช้สคริปต์ไพ ธ อนด้วยเหตุผลหลายประการ ขอบคุณมาก!
Idos

ไม่มีปัญหา. อาจจะเป็นของใช้กับคนอื่น ทำไมถึงสงสัย? ฉันค่อนข้างมั่นใจว่าหลาย ๆ แอพพลิเคชั่นใช้ python อยู่แล้ว
Jacob Vlijm

ส่วนใหญ่เนื่องจากการวางไฟล์. py ที่ใดก็ตามจะมีปัญหาตามที่ฉันต้องสมมติว่ามันอยู่ในที่เดียวกันสำหรับทุกเครื่อง linux ที่จะใช้สคริปต์ของฉัน (และสคริปต์ของฉันทำงานในหลายแพลตฟอร์ม)
Idos

@Idos แค่อยากรู้อยากเห็นซึ่งเป็นแพลตฟอร์ม? Python ค่อนข้างแพร่หลาย ฉันไม่คิดว่าจะติดตั้งบน Mac OS X เป็นค่าเริ่มต้น แต่การกระจาย Linux ส่วนใหญ่จะมี
Sergiy Kolodyazhnyy

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.