Raggruppa i file in alcune cartelle


12

Ho alcuni file con estensioni diverse, come *.pdf, *.mp3, *.jpge pochi altri. Tutti sono memorizzati in una parentdirectory.

Come posso ottenere un elenco di tutte le estensioni, creare alcune cartelle basate su queste estensioni e quindi spostare tutti i file nelle relative cartelle?

Risposte:


13

Lo script python qui sotto fa il lavoro. I file nascosti vengono archiviati separatamente in una cartella, così come i file senza estensione.

Dal momento che potrebbe essere utilizzato per una vasta gamma di scopi, ho aggiunto alcune opzioni:

  • Puoi impostare le estensioni che desideri escludere dalla "riorganizzazione". Se vuoi semplicemente spostare tutto, impostaexclude = ()
  • Puoi scegliere cosa fare con le cartelle vuote ( remove_emptyfolders = Trueo False)
  • Nel caso in cui desideri copiare i file invece di spostarli , sostituisci la riga:
shutil.move(subject, new_dir+"/"+name)

di:

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

Il copione:

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

SE esiste il rischio di sovrascrivere i file duplicati indesiderati

A scapito di alcune righe extra, possiamo evitare di sovrascrivere possibili duplicati. Con il codice seguente, i duplicati verranno rinominati come:

duplicate_1_filename, duplicate_2_filename 

eccetera.

Il copione:

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

MODIFICARE

Con in mente OP, ci siamo tutti dimenticati di aggiungere un'istruzione su come usare. Dal momento che potrebbero apparire ( e fare ) domande duplicate , potrebbe essere comunque utile.

Come usare

  1. Copia uno degli script in un file vuoto, salvalo come reorganize.py
  2. Nella sezione head dello script, imposta la directory target (con i file da riorganizzare):

    reorg_dir = "/path/to/directory_to_reorganize" 

    (usa le virgolette se la directory contiene spazi)

    possibili estensioni che desideri escludere (probabilmente nessuna, come di seguito):

    exclude = ()

    e se desideri rimuovere le cartelle vuote in seguito:

    remove_emptyfolders = True
  3. Esegui lo script con il comando:

    python3 /path/to/reorganize.py

NB se desideri copiare i file anziché spostarli , sostituisci:

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

di:

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

Prova prima un piccolo campione.


12

È possibile utilizzare findcon un execcomando piuttosto complesso :

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

Sostituire cpcon echoper una corsa a secco.


Più efficiente e ordinato sarebbe salvare il bashcomando in uno script (diciamo, a /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

E poi esegui find:

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

Questo approccio è piuttosto flessibile. Ad esempio, per usare il nome del file anziché l'estensione ( filename.ext), dovremmo usarlo per EXT:

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

+1; la -iname '*.*'dovrebbe prendere cura dei casi d'angolo ero preoccupato ... bella idea!
Rmano,

@Rmano non gli *.fig.bako .profile/.bashrc, ma almeno dovrebbe gestire solo file con estensioni. Grazie.
muru,

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

Calcolo dell'elenco delle estensioni (dopo lo spostamento):

ls -d *-DIR

Calcolo dell'elenco delle estensioni (prima di spostarsi):

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

(in quest'ultimo esempio, stiamo calcolando il numero di file per ogni estensione e ordinandolo)


1
scusa: un refuso "mkdir -f" è stato corretto in "mkdir -p" (per ignorare se la

Uniq non dovrebbe essere applicato dopo l'ordinamento? E per favore non analizzare l'output di ls.
muru,

@muru, (parte 1) ls -X garantisce che le estensioni sono ordinate. L'ordinamento finale era solo per ordinare la tabella delle estensioni per numero di occorrenze - pertinenza. (Ho ragione?).

@muru, (parte 2) è ls -X | grep -Po '(?<=\.)(\w+)$'stata la mia prima idea per ottenere l'elenco ordinato delle estensioni. È molto male? Cosa suggerisci?

Ho dimenticato cosa ls -Xfa. Per quanto riguarda il motivo per cui sconsiglio ls, consultare unix.stackexchange.com/q/128985/70524 e unix.stackexchange.com/q/112125/70524 . Per ottenere ciò che fai, farei un modo più lungo: find . -type f -name '*?.?*' -print0 | sed -z 's/.*\.//' | sort -zu(con un opzionale | uniq -cz, se sono necessari conteggi). E find ... -print0 | gawk -v RS='\0'(anche se non è molto portatile ) per il primo.
Muru,

5

Prova questo script di shell.

#!/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
Mi dispiace, è un errore. Dovrei sostituire ogni ricorrenza di filepathcon file. Lo correggerò direttamente.
Prashant Karmakar,

Si prega di non analizzare l'output di ls. Invece, facciafor file in "$src"/*?.?*; do ..
muru il

@muru funzionerà correttamente se il nome di alcuni file ha spazi?
Prashant Karmakar il

@PrashantKarmakar sì, mentre readpotrebbe avere un comportamento inaspettato. Dovresti anche citare le variabili nei comandi mkdir e mv.
Muru,

Provalo, se vuoi:for i in *; do printf "%s\n" "$i"; done; for i in $(ls -d); do printf "%s\n" "$i"; done
muru

2

Se hai installato il nome / nome di Perl:

rename 's!(.*)\.(\w+)$! mkdir($2); "$2/$&"!ge'  *
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.