Como mesclar todos os arquivos em outra pasta em um arquivo e adicionar nova linha

1

Eu tenho muitas pastas e arquivos, esta é a estrutura que tenho

26-09-2016/CHANGELOG_20160926.TXT
26-09-2016/FILE_CHANGELOG_20160926.TXT
27-09-2016/CHANGELOG_20160927.TXT
27-09-2016/FILE_CHANGELOG_20160927.TXT

Eu preciso da saída da seguinte forma. Todos os arquivos com nome como CHANGELOG_*.TXT devem ser mesclados e adicionar nova linha separada em um arquivo como CHANGELOG_20160926-20160930.TXT , e todo o arquivo com nome FILE_CHANGELOG_*.TXT deve ser mesclado e adicionar nova linha separada em um arquivo também como FILE_CHANGELOG_20160926-20160930.TXT . / p>

Como posso fazer isso?

    
por Roman Masyhar 01.10.2016 / 01:53

2 respostas

1

Como você não especificou nenhum requisito de idioma, aqui está uma possibilidade usando o Python 3.

#/usr/bin/env python3

from glob import glob
from os.path import basename
import re

for prefix in ('CHANGELOG', 'FILE_CHANGELOG'):
    files = dict((int(re.split('[_.]', basename(f))[-2]), f)
                 for f in glob('*-*-*/%s_*.TXT' % prefix))
    out_file = '%s_%d-%d.TXT' % (prefix, min(files.keys()), max(files.keys()))

    with open(out_file, 'w') as f_out:
        for date in sorted(files.keys()):
            with open(files[date]) as f_in:
                for line in f_in:
                    f_out.write(line)
            f_out.write("\n")

Ele basicamente usa glob e basename para listar e analisar nomes de arquivos, classificando-os por data. Os valores min / max são usados para construir o nome do arquivo de saída, e todos os arquivos são escritos em ordem. Não se esqueça de ajustar os padrões à sua estrutura de diretórios real, caso seja necessário. Então, apenas chmod e execute:

$ chmod +x script.py
$ ./script.py
    
por 02.10.2016 / 04:51
0

Solução em TXR :

Primeiro, vamos tratar isso como uma tarefa de processamento de texto, supondo que tenhamos a lista de exemplos de nomes de caminho em um arquivo de entrada chamado paths . Transformamos paths em comandos shell que cat dos grupos de arquivos juntos e produzimos os arquivos de saída necessários:

@(do
   (defstruct file-info nil
     full-name
     root-name
     date-key
     (:method equal (self) self.date-key)))
@(collect :vars (files))
@  (all)
@dd-@mm-@yyyy/@*{name}_@yyyy@[email protected]
@  (and)
@path
@  (end)
@  (bind files @(new file-info full-name path root-name name
                     date-key ^(,yyyy ,mm ,dd)))
@(end)
@(do
   (let ((h (group-by (usl root-name) files :equal-based)))
     [hash-update h sort]
     (dohash (name flist h)
       (let ((start (find-min flist))
             (end (find-max flist))
             (paths (mapcar (usl full-name) flist)))
         (put-line 'cat @{paths " "} >\ \
                    @{start.root-name}_@{start.date-key ""}- \
                    @{end.date-key ""}.TXT')))))

Executar:

$ txr catfiles.txr paths
cat 26-09-2016/CHANGELOG_20160926.TXT 27-09-2016/CHANGELOG_20160927.TXT > CHANGELOG_20160926-20160927.TXT
cat 26-09-2016/FILE_CHANGELOG_20160926.TXT 27-09-2016/FILE_CHANGELOG_20160927.TXT > FILE_CHANGELOG_20160926-20160927.TXT

Para trabalhar em caminhos reais e executar os comandos cat , é necessário fazer modificações simples:

@(do
   (defstruct file-info nil
     full-name
     root-name
     date-key
     (:method equal (self) self.date-key)))
@(next :list (glob "*/*.TXT"))
@(collect :vars (files))
@  (all)
@dd-@mm-@yyyy/@*{name}_@yyyy@[email protected]
@  (and)
@path
@  (end)
@  (bind files @(new file-info full-name path root-name name
                     date-key ^(,yyyy ,mm ,dd)))
@(end)
@(do
   (let ((h (group-by (usl root-name) files :equal-based)))
     [hash-update h sort]
     (dohash (name flist h)
       (let ((start (find-min flist))
             (end (find-max flist))
             (paths (mapcar (usl full-name) flist)))
         (sh 'cat @{paths " "} >\ \
              @{start.root-name}_@{start.date-key ""}- \
              @{end.date-key ""}.TXT')))))

As únicas mudanças são a adição de um @(next :list (glob "*/*.TXT")) para redirecionar a varredura de entrada através de uma lista de caminhos globbed do sistema de arquivos, e uma mudança de put-string para sh para ter os comandos cat executados. / p>

Se as listas de arquivos puderem ser muito grandes, nos encontraremos nos limites de passagem do comando / argv do SO: não podemos cat-los em um único comando.

Uma possível correção para isso é alterar a última parte do código para:

@(do
   (let ((h (group-by (usl root-name) files :equal-based)))
     (hash-update h (op sort))
     (dohash (name flist h)
       (let* ((start (find-min flist))
              (end (find-max flist))
              (paths (mapcar (usl full-name) flist))
              (target '@{start.root-name}_@{start.date-key ""}- \
                       @{end.date-key ""}.TXT'))
         (sh '> @target')
         (each ((group-of-ten (tuples 10 paths)))
           (sh 'cat @{group-of-ten " "} >> @target'))))))

Ou seja. para cada arquivo, use > file para garantir que ele exista e seja truncado para zero. Em seguida, use cat ... >> file para anexar os logs a ele, em grupos de dez.

    
por 05.10.2016 / 17:30