将某些文件夹中的文件分组


12

我有不同的扩展名,如一些文件*.pdf*.mp3*.jpg和其他几个人。所有这些都存储在parent目录中。

如何获取所有扩展名的列表,如何基于这些扩展名创建一些文件夹,然后将所有文件移至其相关文件夹中?

Answers:


13

下面的python脚本可以完成这项工作。隐藏的文件和不带扩展名的文件分别存储在一个文件夹中。

由于它可能用于更广泛的用途,因此我添加了一些选项:

  • 您可以设置要从“重组”中排除的扩展程序。如果您只想移动全部,请设置exclude = ()
  • 您可以选择处理空文件夹(remove_emptyfolders = TrueFalse
  • 如果您要复制文件而不是移动文件,请替换以下行:
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 2014年

@Rmano不是“ *.fig.bak或” .profile/.bashrc,但至少应至少处理带有扩展名的文件。谢谢。
穆鲁

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的输出。
muru 2014年

@muru,(第1部分)ls -X保证对扩展名进行排序。最后的排序只是按照出现的次数(相关性)对扩展表进行排序。(我是对的吗?)。

@muru,(第2部分)ls -X | grep -Po '(?<=\.)(\w+)$'是我获得扩展名排序列表的第一个想法。很不好吗 你有什么建议?

我忘记了ls -X。关于我为什么反对的建议ls,请参见unix.stackexchange.com/q/128985/70524unix.stackexchange.com/q/112125/70524。为了完成您的工作,我会走更长的路:(如果需要计数,可以find . -type f -name '*?.?*' -print0 | sed -z 's/.*\.//' | sort -zu使用可选的| uniq -cz)。并且find ... -print0 | gawk -v RS='\0'(尽管那不是很便携)。
muru 2014年

5

试试这个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
对不起,这是一个错误。我应该有取代的每次出现filepathfile。我会直接纠正。
Prashant Karmakar 2014年

请不要解析ls的输出。相反,请做for file in "$src"/*?.?*; do ..
muru

如果某些文件的名称带有空格,则@muru可以正常工作吗?
Prashant Karmakar 2014年

@PrashantKarmakar是的,但是read可能会有意外的行为。您还应该在mkdir和mv命令中引用变量。
muru

如果需要,请测试一下:for i in *; do printf "%s\n" "$i"; done; for i in $(ls -d); do printf "%s\n" "$i"; done
muru

2

如果您安装了Perl的重命名/名称:

rename 's!(.*)\.(\w+)$! mkdir($2); "$2/$&"!ge'  *
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.