Mengelompokkan file dalam beberapa folder

12

Saya punya beberapa file dengan ekstensi yang berbeda seperti *.pdf, *.mp3, *.jpgdan beberapa orang lainnya. Semuanya disimpan dalam parentdirektori.

Bagaimana saya bisa mendapatkan daftar semua ekstensi, membuat beberapa folder berdasarkan ekstensi ini dan kemudian memindahkan semua file ke folder yang relevan?

αғsнιη
sumber

Jawaban:

13

Skrip python di bawah ini berfungsi. File tersembunyi disimpan secara terpisah di folder, serta file tanpa ekstensi.

Karena mungkin digunakan untuk tujuan yang lebih luas, saya menambahkan beberapa opsi:

  • Anda dapat mengatur ekstensi yang ingin Anda kecualikan dari "reorganisasi". Jika Anda hanya ingin memindahkan semua, aturexclude = ()
  • Anda dapat memilih apa yang harus dilakukan dengan folder kosong ( remove_emptyfolders = Trueatau False)
  • Jika Anda ingin menyalin file daripada memindahkannya , ganti baris:
shutil.move(subject, new_dir+"/"+name)

oleh:

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

Naskah:

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

JIKA ada risiko menimpa file duplikat yang tidak diinginkan

Dengan mengorbankan beberapa baris tambahan, kami dapat mencegah menimpa duplikat yang mungkin. Dengan kode di bawah ini, duplikat akan diubah namanya menjadi:

duplicate_1_filename, duplicate_2_filename 

dll.

Naskah:

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

EDIT

Dengan mengingat OP, kita semua lupa menambahkan instruksi tentang cara menggunakan. Karena pertanyaan duplikat mungkin ( dan memang ) muncul, itu mungkin berguna.

Cara Penggunaan

  1. Salin salah satu skrip ke file kosong, simpan sebagai reorganize.py
  2. Di bagian kepala skrip, setel direktori yang ditargetkan (dengan file untuk ditata ulang):

    reorg_dir = "/path/to/directory_to_reorganize" 

    (gunakan tanda kutip jika direktori berisi spasi)

    kemungkinan ekstensi yang ingin Anda kecualikan (mungkin tidak ada, seperti di bawah):

    exclude = ()

    dan jika Anda ingin menghapus folder kosong sesudahnya:

    remove_emptyfolders = True
  3. Jalankan skrip dengan perintah:

    python3 /path/to/reorganize.py

NB jika Anda ingin menyalin file daripada memindahkan , ganti:

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

oleh:

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

Silakan coba dulu pada sampel kecil.

Yakub Vlijm
sumber
12

Anda dapat menggunakan finddengan execperintah yang agak rumit :

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

Ganti cpdengan echountuk lari kering.


Lebih efisien dan rapi akan menyimpan bashperintah dalam skrip (katakanlah, di /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

Dan kemudian jalankan find:

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

Pendekatan ini cukup fleksibel. Misalnya, untuk menggunakan nama file alih-alih ekstensi ( filename.ext), kami akan menggunakan ini untuk EXT:

NAME="${i##*/}"
EXT="${NAME%.*}"
muru
sumber
+1; yang -iname '*.*'harus mengurus kasus sudut saya khawatir tentang ... ide bagus!
Rmano
@Rmano bukan *.fig.bakatau .profile/.bashrcyang, tetapi seharusnya hanya menangani file dengan ekstensi, setidaknya. Terima kasih.
muru
6
ls | gawk -F. 'NF>1 {f= $NF "-DIR"; system("mkdir -p " f ";mv " $0 " " f)}'

Menghitung daftar ekstensi (setelah pindah):

ls -d *-DIR

Menghitung daftar ekstensi (sebelum pindah):

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

(dalam contoh terakhir ini, kami menghitung jumlah file untuk setiap ekstensi dan mengurutkannya)


sumber
1
maaf: salah ketik "mkdir -f" dikoreksi menjadi "mkdir -p" (untuk mengabaikan jika dir sudah ada)
Bukankah uniq seharusnya diterapkan setelah sortir? Dan tolong jangan menguraikan output ls.
muru
@muru, (bagian 1) ls -X menjamin ekstensi diurutkan. Urutan terakhir hanya untuk memesan tabel ekstensi dengan jumlah kemunculan - relevansi. (Aku benar?).
@muru, (bagian 2) ls -X | grep -Po '(?<=\.)(\w+)$'adalah ide pertama saya untuk mendapatkan daftar ekstensi yang diurutkan. Apakah ini sangat buruk? Apa yang Anda sarankan?
Saya lupa apa ls -X. Mengenai mengapa saya merekomendasikan melawan ls, lihat unix.stackexchange.com/q/128985/70524 dan unix.stackexchange.com/q/112125/70524 . Untuk mencapai apa yang Anda lakukan, saya akan menempuh jalan yang lebih panjang: find . -type f -name '*?.?*' -print0 | sed -z 's/.*\.//' | sort -zu(dengan opsional | uniq -cz, jika jumlah diperlukan). Dan find ... -print0 | gawk -v RS='\0'(meskipun itu tidak terlalu portabel ) untuk yang pertama.
muru
5

Coba skrip shell ini.

#!/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.
Prashant Karmakar
sumber
1
Maaf, itu kesalahan. Saya harus mengganti setiap kejadian filepathdengan file. Saya akan memperbaikinya secara langsung.
Prashant Karmakar
Tolong jangan parse output dari ls. Sebaliknya, dofor file in "$src"/*?.?*; do ..
muru
@uru akankah itu bekerja dengan benar jika nama beberapa file memiliki spasi?
Prashant Karmakar
@ PrashantKarmakar ya, sedangkan readmungkin memiliki perilaku yang tidak terduga. Anda juga harus mengutip variabel dalam perintah mkdir dan mv.
muru
Uji, jika Anda akan:for i in *; do printf "%s\n" "$i"; done; for i in $(ls -d); do printf "%s\n" "$i"; done
muru
2

Jika Anda memiliki nama ren / prename Perl yang diinstal:

rename 's!(.*)\.(\w+)$! mkdir($2); "$2/$&"!ge'  *
muru
sumber