Tengo muchas carpetas y archivos, esta es la estructura que tengo
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
Necesito el resultado de la siguiente manera. Todos los archivos con nombres similares CHANGELOG_*.TXT
se fusionarán y agregarán una nueva línea separada en un archivo similar CHANGELOG_20160926-20160930.TXT
, y todos los archivos con nombres FILE_CHANGELOG_*.TXT
se fusionarán y agregarán una nueva línea separada en un archivo similar FILE_CHANGELOG_20160926-20160930.TXT
.
¿Cómo puedo hacer eso?
Respuesta1
Dado que no especificó ningún requisito de idioma, existe la posibilidad de utilizar 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")
Básicamente utiliza glob
y basename
para enumerar y analizar nombres de archivos, clasificándolos por fecha. Los valores mínimo/máximo se utilizan para crear el nombre del archivo de salida, y todos los archivos se escriben allí en orden. No olvide ajustar los patrones a su estructura de directorio real, si fuera necesario. Luego, simplemente chmod
y ejecuta:
$ chmod +x script.py
$ ./script.py
Respuesta2
Solución enTXR:
Primero, tratemos esto como una tarea de procesamiento de texto, asumiendo que tenemos la lista de ejemplo de nombres de rutas en un archivo de entrada llamado paths
. Transformamos paths
en comandos de shell que cat
agrupan archivos y producen los archivos de salida requeridos:
@(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`)))))
Correr:
$ 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 trabajar en rutas reales y ejecutar los cat
comandos se requieren modificaciones 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`)))))
Los únicos cambios son la adición de a @(next :list (glob "*/*.TXT"))
para redirigir el escaneo de entrada a través de una lista de rutas obtenidas del sistema de archivos y un cambio de put-string
a sh
para cat
ejecutar los comandos.
Si las listas de archivos pueden ser muy grandes, nos encontraremos con los límites de paso de comandos/argv del sistema operativo: no podemos capturarlos en un solo comando.
Una posible solución para esto es cambiar la última parte del código a:
@(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`))))))
Es decir, para cada archivo, utilícelo > file
para asegurarse de que exista y esté truncado a cero. Luego utilícelo cat ... >> file
para agregarle los registros, en grupos de diez.