たくさんのフォルダとファイルがあり、これが私の構造です
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
ように 1 つのファイルにマージして、個別の新しい行を追加しCHANGELOG_20160926-20160930.TXT
、FILE_CHANGELOG_*.TXT
のような名前のすべてのファイルを のように 1 つのファイルにマージして、個別の新しい行を追加する必要があります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
シェル コマンドに変換します。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`)))))
唯一の変更点は、@(next :list (glob "*/*.TXT"))
ファイルシステムからグロブされたパスのリストに対して入力スキャンをリダイレクトするための の追加と、コマンドを実行するためput-string
のから へのスイッチの追加です。sh
cat
ファイルのリストが非常に大きくなる可能性がある場合、OS コマンド/引数の受け渡し制限に達し、単一のコマンドでそれらを cat することはできません。
これを修正するには、コードの最後の部分を次のように変更します。
@(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
、10 個ずつのグループでログを追加します。