我有很多文件夹和文件,这是我的结构
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
我需要如下的输出。所有具有类似名称的文件CHANGELOG_*.TXT
都应合并,并将单独的新行添加到一个文件中CHANGELOG_20160926-20160930.TXT
,类似,所有具有名称的文件FILE_CHANGELOG_*.TXT
也应合并,并将单独的新行添加到一个文件中FILE_CHANGELOG_20160926-20160930.TXT
。
我怎样才能做到这一点?
答案1
由于您没有指定任何语言要求,因此可以使用 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")
它基本上使用glob
和basename
来列出和解析文件名,并按日期对它们进行排序。最小/最大值用于构建输出文件名,所有文件都按顺序写入其中。如果有必要,不要忘记将模式调整为实际的目录结构。然后,chmod
运行:
$ chmod +x script.py
$ ./script.py
答案2
解决方案在TXR:
首先,我们将其视为文本处理任务,假设我们有路径名示例列表和名为 的输入文件paths
。我们将文件组转换paths
为 shell 命令并生成所需的输出文件:cat
@(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`)))))
跑步:
$ 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
要在真实路径上工作并执行cat
命令,需要进行简单的修改:
@(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`)))))
唯一的变化是添加了 a@(next :list (glob "*/*.TXT"))
来重定向输入扫描从文件系统中获取的路径列表,以及从 切换put-string
到sh
来cat
执行命令。
如果文件列表可能非常大,我们将遇到操作系统命令/argv 传递限制:我们无法在单个命令中对它们进行分类。
一个可能的解决方法是将代码的最后部分更改为:
@(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`))))))
即对于每个文件,使用它> file
来确保它存在并且被截断为零。然后用于cat ... >> file
将日志以十个为一组附加到其中。