Dosyaları bazı klasörlerde gruplama


12

Ben gibi farklı uzantılara sahip bazı dosyaları var *.pdf, *.mp3, *.jpgve birkaç diğerleri. Hepsi bir parentdizinde saklanır .

Tüm uzantıların listesini nasıl alabilirim, bu uzantılara dayalı bazı klasörler oluşturabilir ve ardından tüm dosyaları ilgili klasörlerine nasıl taşıyabilirim?

Yanıtlar:


13

Aşağıdaki python betiği işi yapar. Gizli dosyalar, bir klasörde ve uzantısız dosyalarda ayrı olarak saklanır.

Çok çeşitli amaçlar için kullanılabileceğinden, birkaç seçenek ekledim:

  • "Yeniden düzenleme" dışında bırakmak istediğiniz uzantıları ayarlayabilirsiniz. Sadece hepsini taşımak istiyorsanız,exclude = ()
  • Boş klasörlerle ( remove_emptyfolders = Trueveya False) ne yapılacağını seçebilirsiniz
  • Dosyaları taşımak yerine kopyalamak istiyorsanız , satırı değiştirin:
shutil.move(subject, new_dir+"/"+name)

tarafından:

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

Senaryo:

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

Yinelenen yinelenen dosyaların üzerine yazma riski varsa

Birkaç ekstra satır pahasına, olası kopyaların üzerine yazılmasını önleyebiliriz. Aşağıdaki kodla, kopyalar şu şekilde yeniden adlandırılacaktır:

duplicate_1_filename, duplicate_2_filename 

vb.

Senaryo:

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

DÜZENLE

OP düşünülerek, hepimiz nasıl kullanılacağına dair bir talimat eklemeyi unuttuk. Yinelenen sorular görünebileceğinden ( ve göründüğünden), yine de faydalı olabilir.

Nasıl kullanılır

  1. Komut dosyalarından birini boş bir dosyaya kopyalayın, reorganize.py
  2. Komut dosyasının baş bölümünde, hedef dizini ayarlayın (yeniden düzenlenecek dosyalarla):

    reorg_dir = "/path/to/directory_to_reorganize" 

    (dizinde boşluk varsa tırnak işaretleri kullanın)

    hariç tutmak istediğiniz olası uzantılar (muhtemelen hiçbiri, aşağıdaki gibi):

    exclude = ()

    ve daha sonra boş klasörleri kaldırmak isterseniz:

    remove_emptyfolders = True
  3. Komut dosyasını şu komutla çalıştırın:

    python3 /path/to/reorganize.py

Not: Dosyaları taşımak yerine kopyalamak istiyorsanız , değiştirin:

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

tarafından:

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

Lütfen önce küçük bir örnek üzerinde deneyin.


12

Sen kullanabilirsiniz findbiraz karmaşık olan execkomuta:

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

Değiştir cpile echokuru çalıştırmak için.


Daha verimli ve daha düzenli bashkomutları bir komut dosyasına (örneğin, at /path/to/the/script.sh) kaydetmek olacaktır :

#! /bin/bash

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

Ve sonra çalıştırın find:

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

Bu yaklaşım oldukça esnektir. Örneğin, uzantı ( filename.ext) yerine dosya adını kullanmak için şunu kullanırız EXT:

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

+ 1; -iname '*.*'Ben yaklaşık ... güzel fikri endişeliydi köşe durumlarda dikkatli olmalıdır!
Rmano

@ *.fig.bakVeya .profile/.bashrcolanları değil, yalnızca en azından uzantıları olan dosyaları işlemelidir . Teşekkürler.
muru

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

Uzantı listesinin hesaplanması (taşındıktan sonra):

ls -d *-DIR

Uzantı listesinin hesaplanması (taşınmadan önce):

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

(bu son örnekte, her uzantı için dosya sayısını hesaplıyor ve sıralıyoruz)


1
üzgünüm: "mkdir -f" yazım hatası "mkdir -p" olarak düzeltildi (dizin zaten yoksa yoksaymak için)

Uniq'in sıralamadan sonra uygulanması gerekmez mi? Ve ls çıktısını ayrıştırmayın lütfen.
muru

@muru, (part 1) ls -X uzantıların sıralanmasını garanti eder. Son sıralama, uzantılar tablosunu olay sayısına - alaka düzeyine göre sıralamaktı. (Doğruyum?).

@muru, (bölüm 2) ls -X | grep -Po '(?<=\.)(\w+)$'sıralı uzantı listesini almak için ilk fikrimdi. Çok mu kötü? Sen ne önerirsin?

Ne yaptığını unuttum ls -X. Niçin karşı önerdiğime gelince ls, bkz. Unix.stackexchange.com/q/128985/70524 ve unix.stackexchange.com/q/112125/70524 . Yaptığın şeyi başarmak için daha uzun bir yoldan gideceğim: find . -type f -name '*?.?*' -print0 | sed -z 's/.*\.//' | sort -zu( | uniq -czsayım gerekiyorsa isteğe bağlı olarak). Ve find ... -print0 | gawk -v RS='\0'(bu çok taşınabilir olmasa da ) birincisi için.
muru

5

Bu kabuk komut dosyasını deneyin.

#!/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
Üzgünüm, bu bir hatadır. Her geçtiği yer değiştirmiş için gerekenden filepathile file. Bunu doğrudan düzeltirim.
Prashant Karmakar

Lütfen ls çıkışını ayrıştırmayın. Bunun yerine, yapınfor file in "$src"/*?.?*; do ..
muru

@muru bazı dosya adında boşluk varsa bu düzgün çalışır?
Prashant Karmakar

@PrashantKarmakar evet, readbeklenmedik davranışlar gösterebilir. Ayrıca mkdir ve mv komutlarındaki değişkenleri de tırnak içine almalısınız.
muru

Eğer test edin, eğer:for i in *; do printf "%s\n" "$i"; done; for i in $(ls -d); do printf "%s\n" "$i"; done
muru

2

Perl'in yeniden adlandırmasını / ön adını yüklemişseniz:

rename 's!(.*)\.(\w+)$! mkdir($2); "$2/$&"!ge'  *
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.