Nhóm tệp trong một số thư mục


12

Tôi có một số file với phần mở rộng khác nhau như *.pdf, *.mp3, *.jpgvà một vài người khác. Tất cả chúng được lưu trữ trong một parentthư mục.

Làm cách nào tôi có thể nhận danh sách tất cả các tiện ích mở rộng, tạo một số thư mục dựa trên các tiện ích mở rộng này và sau đó di chuyển tất cả các tệp vào các thư mục có liên quan của chúng?

Câu trả lời:


13

Kịch bản python dưới đây thực hiện công việc. Các tệp ẩn được lưu trữ riêng trong một thư mục, cũng như các tệp không có phần mở rộng.

Vì nó có thể được sử dụng cho nhiều mục đích hơn, tôi đã thêm một vài tùy chọn:

  • Bạn có thể đặt tiện ích mở rộng mà bạn muốn loại trừ khỏi "sắp xếp lại". Nếu bạn chỉ muốn di chuyển tất cả, hãy đặtexclude = ()
  • Bạn có thể chọn làm gì với các thư mục trống ( remove_emptyfolders = Truehoặc False)
  • Trong trường hợp bạn muốn sao chép các tệp thay vì di chuyển chúng, hãy thay thế dòng:
shutil.move(subject, new_dir+"/"+name)

bởi:

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

Kịch bản:

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

NẾU có nguy cơ ghi đè lên các tệp trùng lặp không mong muốn

Với chi phí của một vài dòng bổ sung, chúng tôi có thể ngăn chặn việc ghi đè lên các bản sao có thể. Với mã bên dưới, các bản sao sẽ được đổi tên thành:

duplicate_1_filename, duplicate_2_filename 

Vân vân.

Kịch bản:

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

BIÊN TẬP

Với OP trong tâm trí, tất cả chúng ta đều quên thêm một hướng dẫn về cách sử dụng. Vì các câu hỏi trùng lặp có thể ( và làm ) xuất hiện, tuy nhiên nó có thể hữu ích.

Cách sử dụng

  1. Sao chép một trong các tập lệnh vào một tệp trống, lưu nó dưới dạng reorganize.py
  2. Trong phần đầu của tập lệnh, đặt thư mục được nhắm mục tiêu (với các tệp để sắp xếp lại):

    reorg_dir = "/path/to/directory_to_reorganize" 

    (sử dụng dấu ngoặc kép nếu thư mục chứa dấu cách)

    các tiện ích mở rộng có thể bạn muốn loại trừ (có thể không có, như bên dưới):

    exclude = ()

    và nếu bạn muốn xóa các thư mục trống sau đó:

    remove_emptyfolders = True
  3. Chạy đoạn script với lệnh:

    python3 /path/to/reorganize.py

NB nếu bạn muốn sao chép các tập tin thay vì di chuyển , thay thế:

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

bởi:

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

Vui lòng thử đầu tiên trên một mẫu nhỏ.


12

Bạn có thể sử dụng findvới một execlệnh hơi phức tạp :

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

Thay thế cpvới echomột chạy khô.


Hiệu quả và gọn gàng hơn sẽ là lưu bashlệnh trong một tập lệnh (giả sử, tại /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

Và sau đó chạy find:

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

Cách tiếp cận này khá linh hoạt. Ví dụ: để sử dụng tên tệp thay vì phần mở rộng ( filename.ext), chúng tôi sẽ sử dụng tên này cho EXT:

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

+1; các -iname '*.*'nên chăm sóc các trường hợp góc Tôi đã lo lắng về ... ý tưởng tốt đẹp!
Rmano

@Rmano không phải *.fig.bakhoặc .profile/.bashrccái, nhưng ít nhất nó chỉ nên xử lý các tệp có phần mở rộng. Cảm ơn.
muru

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

Tính toán danh sách các tiện ích mở rộng (sau khi di chuyển):

ls -d *-DIR

Tính toán danh sách các tiện ích mở rộng (trước khi di chuyển):

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

(trong ví dụ cuối cùng này, chúng tôi đang tính toán số lượng tệp cho mỗi tiện ích mở rộng và sắp xếp nó)


1
xin lỗi: một lỗi đánh máy "mkdir -f" đã được sửa thành "mkdir -p" (bỏ qua nếu dir đã tồn tại)

Không phải uniq sẽ được áp dụng sau khi sắp xếp sao? Và xin đừng phân tích đầu ra của ls.
muru

@muru, (phần 1) ls -X đảm bảo rằng các tiện ích mở rộng được sắp xếp. Sắp xếp cuối cùng chỉ là để đặt hàng bảng mở rộng theo số lần xuất hiện - mức độ liên quan. (Tôi có đúng không?).

@muru, (phần 2) ls -X | grep -Po '(?<=\.)(\w+)$'là ý tưởng đầu tiên của tôi để có được danh sách các phần mở rộng được sắp xếp. Có phải nó rất xấu? Bạn có đề nghị gì?

Tôi quên mất những gì ls -Xkhông. Về lý do tại sao tôi khuyên bạn nên lsxem, hãy xem unix.stackexchange.com/q/128985/70524unix.stackexchange.com/q/112125/70524 . Để đạt được những gì bạn làm, tôi sẽ đi một chặng đường dài hơn: find . -type f -name '*?.?*' -print0 | sed -z 's/.*\.//' | sort -zu(với một tùy chọn | uniq -cz, nếu cần số lượng). Và find ... -print0 | gawk -v RS='\0'(mặc dù điều đó không phảirất di động ) cho lần đầu tiên.
muru

5

Hãy thử kịch bản shell này.

#!/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
Tôi xin lỗi, đó là một lỗi. Tôi phải thay thế mỗi lần xuất hiện filepathvới file. Tôi sẽ sửa nó trực tiếp.
Prashant Karmakar

Xin đừng phân tích đầu ra của ls. Thay vào đó, hãy làmfor file in "$src"/*?.?*; do ..
muru 30/12/14

@muru sẽ hoạt động chính xác nếu tên của một số tệp có khoảng trắng?
Prashant Karmakar

@PrashantKarmakar có, trong khi readcó thể có hành vi bất ngờ. Bạn cũng nên trích dẫn các biến trong lệnh mkdir và mv.
muru

Hãy thử đi, nếu bạn sẽ:for i in *; do printf "%s\n" "$i"; done; for i in $(ls -d); do printf "%s\n" "$i"; done
muru

2

Nếu bạn đã cài đặt tên / tên của Perl:

rename 's!(.*)\.(\w+)$! mkdir($2); "$2/$&"!ge'  *
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.