一部のフォルダー内のファイルをグループ化する


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

注意moveの代わりにファイルをコピーしたい場合は、次を置き換えます:

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

乾式運転の場合に交換cpechoてください。


より効率的で整頓されているのは、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 14

@Rmanoは1 *.fig.bakつまたは複数ではありませんが、.profile/.bashrc少なくとも拡張子を持つファイルのみを処理する必要があります。ありがとう。
ムル14

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の出力を解析しないでください。
ムル14

@muru、(パート1)ls -Xは、拡張機能がソートされることを保証します。最終的な並べ替えは、拡張テーブルを出現回数順に並べることでした-関連性。(私は正しいですか?)。

@muru(パート2)ls -X | grep -Po '(?<=\.)(\w+)$'は、拡張機能のソートされたリストを取得する最初のアイデアでした。それは非常に悪いですか?何を指示してるんですか?

何を忘れたls -X。反対する理由についてはlsunix.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'(それはあまりポータブルではありませんが)最初のものです。
ムル14

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コマンドで変数を引用する必要があります。
ムル14

あなたがするなら、それをテストしてください:for i in *; do printf "%s\n" "$i"; done; for i in $(ls -d); do printf "%s\n" "$i"; done
muru 14

2

Perlのrename / prenameがインストールされている場合:

rename 's!(.*)\.(\w+)$! mkdir($2); "$2/$&"!ge'  *
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.