サイズを小さくする必要があるファイルが多すぎます。私はほとんどの(すべてではない)ファイルに情報を失うことなく切り取ることができる終わりセクションがあることを発見しました。
Data 1
Data 2
something_unimportant_here END DATA
Rubbish 1
Rubbish 2
「END DATA」を含む行とその後のすべての行を削除し、そのパターンを含むファイルのみを変更してファイル(したがってすべて終了)を編集するにはどうすればよいですか?これにより、ディスクへの書き込みアクセスが最小限に抑えられます(多くのファイルと遅いディスク)。
可能であれば、ファイルの構文が正しいままになるように、ファイルに新しい最後の行(マイクローズタグ)を追加したいと思います。繰り返しますが、パターンを含むファイルでのみ可能です。
私はed
次のようなものを使うつもりです。
echo ',s/END DATA/ ???? '\\n'q'\\n'wq' | ed "$file"
ところで管理できないようですね? ? ?部分的に本当です。
予想出力:
Data 1
Data 2
NEW END
答え1
sed -i
// perl -i
/ ¹などのファイルの新しいコピーを作成するのではなく、ファイルを直接カットしてこれを行うことがed
できるはずです。gawk -i /usr/share/awk/inplace.awk
使用perl
:
find . -name '*.txt' -type f -exec perl -ne '
BEGIN{@ARGV=map{"+<$_"}@ARGV} # open files in read+write mode in the
# while(<>) loop implied by -n
if (/END DATA/) {
seek ARGV,-length,1; # back to beginning of matching line
print ARGV "NEW END\n";
truncate ARGV, tell ARGV;
close ARGV; # skip to next file
}' {} +
perl
一致するものが見つかると、読み取りは停止され、それが NEW END\n
記録される唯一のものであるため、I / Oが最小化されます。また、内部書き込みを行うため、ファイルメタデータ(所有権、権限、acl、スパース...)が保存され、ハードリンクが破損することはありません。
-exec {} +
通話回数も最小限に抑えることができますperl
。
^使用しないでください-i inplace
現在の作業ディレクトリから最初に拡張機能をgawk
ロードしようとすると、誰かがそのディレクトリにマルウェアを植えた可能性があります。システムに付属の拡張プログラムのパスは異なる場合があります。出力を参照してください。inplace
inplace
inplace.awk
inplace
gawk
gawk 'BEGIN{print ENVIRON["AWKPATH"]}'
答え2
探しているコマンドシーケンスは次のとおりです。
/END DATA/,$d
q
.a
NEW END
.
wq
または一行で
printf '%s\n' '/END DATA/,$d' 'q' '.a' 'NEW END' '.' 'wq'
wq
(テストで置き換え可能です,p
。)
前任者。与えられた
$ cat file
Data 1
Data 2
something_unimportant_here END DATA
Rubbish 1
Rubbish 2
それから
$ printf '%s\n' '/END DATA/,$d' 'q' '.a' 'NEW END' '.' 'wq' | ed -s file
与えられた
$ cat file
Data 1
Data 2
NEW END
答え3
そしてGNU grep
GNU sed
grep -lZ 'END DATA' *.txt | xargs -0 sed -i -e '/END DATA/,${//i foo' -e 'd}'
これは、すべてのファイルが拡張子で終わる現在のディレクトリに*.txt
あると仮定します。.txt
ファイルを繰り返し検索する必要がある場合は、オプションもサポートされGNU grep
ます-r/-R
。
/END DATA/,$
動作ライン範囲
//i foo
これは//
以前に使用された正規表現と一致します。/END DATA/
つまり、i
コマンドは必要に応じて新しいクローズタグを追加します。
i
コマンドは改行で区切る必要があるため、オプションは-e
範囲d
に一致するすべての行を削除するためにコマンドを区切るために使用されます。
代わりにこの方法を使用することもできますが、一度に1つのファイルのみが渡されますsed
。
grep -lZ 'END DATA' *.txt | xargs -0 -n1 sed -i -e '/END DATA/{i foo' -e 'Q}'
答え4
このpython
3.8ソリューションは、Stephaneの内部ソリューションに大まかに基づいています。truncate
解決策いくつかの違いがあります。 1.コードはディレクトリナビゲーションのために外部ユーティリティに依存しません。 2.ファイルは、END DATA
文字列の検索を容易にするためにメモリマップされます。
コードを.py
ファイルに入れ、ディレクトリ名をパラメータとして渡します。
import mmap
import os
import sys
from contextlib import closing
def yield_all_files(dir_):
for root, dir_, files in os.walk(dir_):
yield from (os.path.join(root, file_) for file_ in files if file_.endswith('.txt'))
if __name__ == '__main__':
old = b'END DATA'
new = b'NEW END\n'
dir_ = sys.argv[1]
for file_ in yield_all_files(dir_):
with open(file_, mode='r+b') as f:
with closing(mmap.mmap(f.fileno(), length=0, access=mmap.ACCESS_WRITE)) as mm:
if (loc := mm.find(old)) > -1:
mm.seek(loc)
mm.write(new)
mm.resize(mm.tell())