他のフォルダ内のすべてのファイルを 1 つのファイルに結合して改行を追加する方法

他のフォルダ内のすべてのファイルを 1 つのファイルに結合して改行を追加する方法

たくさんのフォルダとファイルがあり、これが私の構造です

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.TXTFILE_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のから へのスイッチの追加です。shcat

ファイルのリストが非常に大きくなる可能性がある場合、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 個ずつのグループでログを追加します。

関連情報