É possível que eu esteja entendendo mal o que você está perguntando aqui, mas como dito, acho que esta pergunta tem algumas sutilezas e requer uma solução relativamente sofisticada, ou seja, não sei quão simples um script pode ser vai fazer o que quiser. Por exemplo, vamos analisar cuidadosamente sua lista de arquivos de exemplo:
aaa.txt
temp-203981.log
temp-098723.log
temp-123197.log
temp-734692.log
test1.sh
test2.sh
test3.sh
De acordo com a sua pergunta, você deseja que os prefixos extraídos desta lista sejam temp
e test
, em que aaa
é excluído, pois há apenas um arquivo com aaa
como prefixo e seu limite de exemplo é três. Mas por que não é te
um prefixo, pois há 7 arquivos que começam com te
? Ou, como parece que você deseja primeiro agrupar os arquivos com base nos sufixos de nome de arquivo, por que um dos novos subdiretórios não é t.log
ou temp-.log
em vez de temp.log
? Espero que esta discussão deixe claro que, se você realmente quer que seu programa determine os prefixos potenciais por si próprio sem ter uma lista de prefixos como argumento, então há algumas ambiguidades em sua declaração de questão que precisam ser resolvidas (e algumas escolhas correspondentes). que precisam ser feitas).
Aqui está um script Python que usa uma estrutura de dados simples trie para pesquisar os prefixos de correspondência mais longos que satisfazem algumas restrições (que pode ser fornecido como argumentos):
#!/usr/bin/env python2
# -*- coding: ascii -*-
"""
trieganize.py
Use the trie data structure to look for prefixes of filenames in a given
directory and then reorganiz those files into subdirectories based on
those prefixes.
In this script the trie data structure is just a dictionary of the
following form:
trie = {
"count": integer,
"children": dictionary,
"leaf": boolean
}
Where the dictionary keys have the following semantics.
count:
stores the number of total descendents of the given trie node
children:
stores the child trie nodes of the given node
leaf:
denotes whether this trie corresponds to the final character in a word
"""
import sys
import os
import string
def add_word_to_trie(trie, word):
"""Add a new word to the trie."""
if word:
trie["count"] += 1
if word[0] not in trie["children"]:
trie["children"][word[0]] = \
{"count": 0, "children": {}, "leaf": False}
add_word_to_trie(trie=trie["children"][word[0]], word=word[1:])
else:
trie["leaf"] = True
return(trie)
def expand_trie(trie, prefix='', words=None):
"""Given a trie, return the list of words it encodes."""
if words is None:
words = list()
if trie["leaf"]:
words.append(prefix)
for character, child in trie["children"].iteritems():
if trie["children"]:
expand_trie(trie=child, prefix=prefix+character, words=words)
return(words)
def extract_groups_from_trie(
trie, threshold=0, prefix='', groups=None,
minimum_prefix_length=0,
maximum_prefix_length=float("inf"),
prefix_charset=string.ascii_letters,
):
"""Given a trie and some prefix constraints, return a dictionary which
groups together the words in the trie based on shared prefixes which
satisfy the specified constraints.
"""
if groups is None:
groups = dict()
if trie["count"] >= threshold:
children = {
character: child
for character, child in trie["children"].iteritems()
if (
child["count"] >= threshold and
len(prefix) + 1 >= minimum_prefix_length and
len(prefix) + 1 <= maximum_prefix_length and
character in prefix_charset
)
}
if not children:
groups[prefix] = expand_trie(trie, prefix)
else:
for character, child in children.iteritems():
extract_groups_from_trie(
trie=child, threshold=threshold,
prefix=prefix+character, groups=groups
)
return(groups)
def reorganize_files(basedir, suffix_separator='.', threshold=3):
"""Takes a path to a directory and reorganizes the files in that
directory into subdirectories based on the prefixes of their
filenames."""
# Get the list of file names
filenames = os.listdir(basedir)
# Group the filenames by suffix
suffixes = {}
for filename in filenames:
basename, separator, suffix = filename.rpartition(suffix_separator)
if suffix not in suffixes:
suffixes[suffix] = []
suffixes[suffix].append(basename)
# For each suffix, search for prefixes
for suffix, basenames in suffixes.iteritems():
# Initialize a trie object
trie = {"count":0, "children": {}, "leaf": False}
# Add the filenames to the trie
for basename in basenames:
add_word_to_trie(trie, basename)
# Break the filenames up into groups based on their prefixes
groups = extract_groups_from_trie(trie, threshold)
# Organize the groups of files into subdirectories
for prefix, group in groups.iteritems():
targetdir = os.path.join(basedir, prefix + suffix_separator + suffix)
os.mkdir(targetdir)
for basename in group:
filename = basename + suffix_separator + suffix
sourcefile = os.path.join(basedir, filename)
targetfile = os.path.join(targetdir, filename)
os.rename(sourcefile, targetfile)
if __name__=="__main__":
reorganize_files(basedir=sys.argv[1])
Para demonstrar este script Python, escrevi um pequeno script de shell para criar e preencher um diretório de teste:
#!/usr/bin/bash
# create-test-dir.sh
rm -rf /tmp/testdir
mkdir -p /tmp/testdir
files=(
aaa.txt
temp-203981.log
temp-098723.log
temp-123197.log
temp-734692.log
test1.sh
test2.sh
test3.sh
)
for file in ${files[@]}; do touch "/tmp/testdir/${file}"; done
Podemos executar o script:
bash create-test-dir.sh
Em seguida, nosso diretório de teste é semelhante a este (executar tree /tmp/testdir
):
/tmp/testdir/
|-- aaa.txt
|-- temp-098723.log
|-- temp-123197.log
|-- temp-203981.log
|-- temp-734692.log
|-- test1.sh
|-- test2.sh
'-- test3.sh
0 directories, 8 files
Agora podemos executar o script Python:
python trieganize.py /tmp/testdir
E depois os arquivos são organizados da seguinte forma:
/tmp/testdir/
|-- aaa.txt
|-- temp.log
| |-- temp-098723.log
| |-- temp-123197.log
| |-- temp-203981.log
| '-- temp-734692.log
'-- test.sh
|-- test1.sh
|-- test2.sh
'-- test3.sh
2 directories, 8 files