จัดกลุ่มไฟล์ในบางโฟลเดอร์


12

ฉันมีบางไฟล์ที่มีนามสกุลที่แตกต่างกันเช่น*.pdf, *.mp3, *.jpgและอื่น ๆ น้อย พวกเขาทั้งหมดจะถูกเก็บไว้ในparentไดเรกทอรี

ฉันจะรับรายการส่วนขยายทั้งหมดสร้างโฟลเดอร์ตามส่วนขยายเหล่านี้แล้วย้ายไฟล์ทั้งหมดไปยังโฟลเดอร์ที่เกี่ยวข้องได้อย่างไร

คำตอบ:


13

สคริปต์ python ด้านล่างทำงานได้ ไฟล์ที่ซ่อนจะถูกจัดเก็บแยกต่างหากในโฟลเดอร์รวมถึงไฟล์ที่ไม่มีนามสกุล

เนื่องจากอาจใช้สำหรับวัตถุประสงค์ที่กว้างขึ้นฉันจึงเพิ่มตัวเลือก:

  • คุณสามารถตั้งค่าส่วนขยายที่คุณต้องการแยกออกจาก "การจัดระเบียบใหม่" หากคุณต้องการย้ายทั้งหมดให้ตั้งค่าexclude = ()
  • คุณสามารถเลือกว่าจะทำอย่างไรกับโฟลเดอร์ว่างเปล่า ( remove_emptyfolders = TrueหรือFalse)
  • ในกรณีที่คุณต้องการคัดลอกไฟล์แทนที่จะย้ายไฟล์ให้แทนที่บรรทัด:
shutil.move(subject, new_dir+"/"+name)

โดย:

shutil.copy(subject, new_dir+"/"+name) 

บท:

#!/usr/bin/env python3

import os
import subprocess
import shutil

# --------------------------------------------------------
reorg_dir = "/path/to/directory_to_reorganize"
exclude = (".jpg") # for example
remove_emptyfolders = True
# ---------------------------------------------------------

for root, dirs, files in os.walk(reorg_dir):
    for name in files:
        subject = root+"/"+name
        if name.startswith("."):
            extension = ".hidden_files"
        elif not "." in name:
            extension = ".without_extension"
        else:
            extension = name[name.rfind("."):]
        if not extension in exclude:
            new_dir = reorg_dir+"/"+extension[1:]
            if not os.path.exists(new_dir):
                os.mkdir(new_dir)
            shutil.move(subject, new_dir+"/"+name)

def cleanup():
    filelist = []
    for root, dirs, files in os.walk(reorg_dir):
        for name in files:
            filelist.append(root+"/"+name)
    directories = [item[0] for item in os.walk(reorg_dir)]
    for dr in directories:
        matches = [item for item in filelist if dr in item]
        if len(matches) == 0:
            try:
                shutil.rmtree(dr)
            except FileNotFoundError:
                pass

if remove_emptyfolders == True:
    cleanup()

หากมีความเสี่ยงต่อการเขียนทับไฟล์ที่ไม่ต้องการ

ด้วยค่าใช้จ่ายเพิ่มเติมสองสามบรรทัดเราสามารถป้องกันการเขียนทับซ้ำที่อาจเกิดขึ้นได้ ด้วยรหัสด้านล่างรายการซ้ำจะถูกเปลี่ยนชื่อเป็น:

duplicate_1_filename, duplicate_2_filename 

เป็นต้น

บท:

#!/usr/bin/env python3

import os
import subprocess
import shutil

# --------------------------------------------------------
reorg_dir = "/path/to/directory_to_reorganize"
exclude = (".jpg") # for example
remove_emptyfolders = True
# ---------------------------------------------------------

for root, dirs, files in os.walk(reorg_dir):
    for name in files:
        subject = root+"/"+name
        if name.startswith("."):
            extension = ".hidden_files"
        elif not "." in name:
            extension = ".without_extension"
        else:
            extension = name[name.rfind("."):]
        if not extension in exclude:
            new_dir = reorg_dir+"/"+extension[1:]
            if not os.path.exists(new_dir):
                os.mkdir(new_dir)
            n = 1; name_orig = name
            while os.path.exists(new_dir+"/"+name):
                name = "duplicate_"+str(n)+"_"+name_orig
                n = n+1
            newfile = new_dir+"/"+name
            shutil.move(subject, newfile)

def cleanup():
    filelist = []
    for root, dirs, files in os.walk(reorg_dir):
        for name in files:
            filelist.append(root+"/"+name)
    directories = [item[0] for item in os.walk(reorg_dir)]
    for dr in directories:
        matches = [item for item in filelist if dr in item]
        if len(matches) == 0:
            try:
                shutil.rmtree(dr)
            except FileNotFoundError:
                pass

if remove_emptyfolders == True:
    cleanup()

แก้ไข

ด้วย OP ในใจเราทุกคนลืมที่จะเพิ่มคำแนะนำเกี่ยวกับวิธีการใช้ ตั้งแต่คำถามที่ซ้ำกันอาจจะ ( และไม่ ) ปรากฏขึ้นก็อาจจะมีประโยชน์ แต่อย่างไรก็ตาม

วิธีใช้

  1. คัดลอกสคริปต์ตัวใดตัวหนึ่งลงในไฟล์เปล่าแล้วบันทึกเป็น reorganize.py
  2. ในส่วนหัวของสคริปต์ให้ตั้งค่าไดเรกทอรีเป้าหมาย (ด้วยไฟล์ที่จะจัดระเบียบใหม่):

    reorg_dir = "/path/to/directory_to_reorganize" 

    (ใช้เครื่องหมายคำพูดหากไดเรกทอรีมีช่องว่าง)

    ส่วนขยายที่เป็นไปได้ที่คุณต้องการยกเว้น (อาจไม่มีเช่นด้านล่าง):

    exclude = ()

    และหากคุณต้องการลบโฟลเดอร์ว่างในภายหลัง:

    remove_emptyfolders = True
  3. รันสคริปต์ด้วยคำสั่ง:

    python3 /path/to/reorganize.py

หมายเหตุหากคุณต้องการคัดลอกไฟล์แทนที่จะย้ายให้แทนที่:

shutil.move(subject, new_dir+"/"+name)

โดย:

shutil.copy(subject, new_dir+"/"+name)

โปรดลองเป็นกลุ่มตัวอย่างก่อน


12

คุณสามารถใช้findกับexecคำสั่งที่ค่อนข้างซับซ้อน:

find . -iname '*?.?*' -type f -exec bash -c 'EXT="${0##*.}"; mkdir -p "$PWD/${EXT}_dir"; cp --target-directory="$PWD/${EXT}_dir" "$0"' {} \;

# '*?.?*' requires at least one character before and after the '.', 
# so that files like .bashrc and blah. are avoided.
# EXT="${0##*.}" - get the extension
# mkdir -p $PWD/${EXT}_dir - make the folder, ignore if it exists

แทนที่cpด้วยechoสำหรับการแห้ง


มีประสิทธิภาพมากขึ้นและเป็นระเบียบมากขึ้นคือการบันทึกbashคำสั่งในสคริปต์ (พูดที่ /path/to/the/script.sh):

#! /bin/bash

for i
do
    EXT="${i##*.}" 
    mkdir -p "$PWD/${EXT}_dir"
    mv --target-directory="$PWD/${EXT}_dir" "$i" 
done

จากนั้นเรียกใช้find:

find . -iname '*?.?*' -type f -exec /path/to/the/script.sh {} +

วิธีนี้ค่อนข้างยืดหยุ่น ตัวอย่างเช่นหากต้องการใช้ชื่อไฟล์แทนส่วนขยาย ( filename.ext) เราจะใช้สิ่งนี้เพื่อEXT:

NAME="${i##*/}"
EXT="${NAME%.*}"

+1; -iname '*.*'ควรดูแลกรณีมุมที่ผมเป็นห่วงเกี่ยวกับ ... ความคิดที่ดี!
Rmano

@Rmano ไม่ใช่*.fig.bakหรือ.profile/.bashrcอันใดอันหนึ่ง แต่ควรจัดการกับไฟล์ที่มีนามสกุลอย่างน้อย ขอบคุณ
muru

6
ls | gawk -F. 'NF>1 {f= $NF "-DIR"; system("mkdir -p " f ";mv " $0 " " f)}'

การคำนวณรายการส่วนขยาย (หลังจากย้าย):

ls -d *-DIR

การคำนวณรายการส่วนขยาย (ก่อนที่จะย้าย):

ls -X | grep -Po '(?<=\.)(\w+)$'| uniq -c | sort -n

(ในตัวอย่างล่าสุดนี้เรากำลังคำนวณจำนวนไฟล์สำหรับแต่ละส่วนขยายและเรียงลำดับ)


1
ขออภัย: พิมพ์ผิด "mkdir -f" ถูกแก้ไขเป็น "mkdir -p" (เพื่อไม่สนใจว่ามี dir อยู่แล้ว)

ไม่ควรใช้ uniq หลังจากจัดเรียงหรือไม่ และโปรดอย่าแยกเอาต์พุตของ ls
muru

@muru, (ส่วนที่ 1) ls -X รับประกันว่าส่วนขยายจะถูกจัดเรียง การเรียงลำดับสุดท้ายเป็นเพียงการสั่งซื้อตารางส่วนขยายตามจำนวนครั้งที่เกิดขึ้น - ความเกี่ยวข้อง (ฉันถูกต้องไหม?)

@muru (ตอนที่ 2) ls -X | grep -Po '(?<=\.)(\w+)$'เป็นความคิดแรกของฉันที่จะได้รับรายการส่วนขยายที่เรียงลำดับแล้ว มันแย่มากเหรอ? คุณแนะนำอะไร?

ฉันลืมสิ่งที่ls -Xทำ ว่าทำไมฉันแนะนำต่อlsให้ดูunix.stackexchange.com/q/128985/70524และunix.stackexchange.com/q/112125/70524 เพื่อให้บรรลุสิ่งที่คุณทำฉันจะไปอีกทาง: find . -type f -name '*?.?*' -print0 | sed -z 's/.*\.//' | sort -zu(พร้อมตัวเลือก| uniq -czถ้าจำเป็นต้องนับ) และfind ... -print0 | gawk -v RS='\0'(แม้ว่าจะไม่ได้พกพาได้มาก ) สำหรับครั้งแรก
muru

5

ลองเชลล์สคริปต์นี้

#!/bin/sh
src=`dirname "$1"`/`basename "$1"`;
for file in "$src"/*?.?*; do
  if test -f "$file"; then
    dest="$src${file##*.}"_files;
    mkdir -p "$dest";
    mv "$file" "$dest";
  fi;
done;

# pass the directory to re-organize as first argument
# moves only regular files which have extension
# ignores other type of files including
# files having no extension, hidden files, directories, and links.

1
ฉันขอโทษนั่นเป็นข้อผิดพลาด ฉันควรจะต้องทดแทนทุกเกิดกับfilepath fileฉันจะแก้ไขให้ถูกต้องโดยตรง
Prashant Karmakar

โปรดอย่าแยกเอาต์พุตของ ls แต่ทำตามfor file in "$src"/*?.?*; do ..
muru

@muru จะทำงานได้อย่างถูกต้องหรือไม่หากชื่อไฟล์บางไฟล์มีช่องว่าง
Prashant Karmakar

@PrashantKarmakar ใช่ในขณะที่readอาจมีพฤติกรรมที่ไม่คาดคิด คุณควรอ้างอิงตัวแปรในคำสั่ง mkdir และ mv
muru

ลองทดสอบดูถ้าคุณจะ:for i in *; do printf "%s\n" "$i"; done; for i in $(ls -d); do printf "%s\n" "$i"; done
muru

2

หากคุณมีการติดตั้งเปลี่ยนชื่อ / prename ของ Perl:

rename 's!(.*)\.(\w+)$! mkdir($2); "$2/$&"!ge'  *
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.