私はかなり大きなファイル(35 Gb)を持っていて、このファイルを内部でフィルタリングしたいと思います(たとえば、他のファイルのための十分なディスク容量がありません)。特にgrepを実行し、いくつかのパターンを無視したいと思います。方法はありますか?他のファイルを使用せずにこれを?
foo:
以下を含むすべての行をフィルタリングしたいとします。
ベストアンサー1
これはシステムコールレベルで可能です。プログラムは、ターゲットファイルを切り捨てることなく書き込み用に開くことができ、標準入力から読み取った内容を書き込み始めることができます。 EOFを読み込むと出力ファイルが切り捨てられることがあります。
入力から行をフィルタリングするため、出力ファイルの書き込み位置は常に読み取り位置より小さくなければなりません。これは、新しい出力で入力が破損してはならないことを意味します。
ただし、これを実行できるプログラムを見つけることは問題です。dd(1)
を開くときに出力ファイルを切り捨てないオプションがありますが、conv=notrunc
末尾でも切り捨てられず、元のファイルコンテンツがgrepコンテンツの後に残ります(同様のコマンドを使用grep pattern bigfile | dd of=bigfile conv=notrunc
)。
システムコールの観点からは非常に簡単なので、小さなプログラムを書いて、小さな(1MiB)フルループバックファイルシステムでテストしました。必要に応じて動作しますが、まず別のファイルでテストしたいと思います。ファイルを上書きすることは常に危険です。
オーバーライド.c
/* This code is placed in the public domain by camh */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char **argv)
{
int outfd;
char buf[1024];
int nread;
off_t file_length;
if (argc != 2) {
fprintf(stderr, "usage: %s <output_file>\n", argv[0]);
exit(1);
}
if ((outfd = open(argv[1], O_WRONLY)) == -1) {
perror("Could not open output file");
exit(2);
}
while ((nread = read(0, buf, sizeof(buf))) > 0) {
if (write(outfd, buf, nread) == -1) {
perror("Could not write to output file");
exit(4);
}
}
if (nread == -1) {
perror("Could not read from stdin");
exit(3);
}
if ((file_length = lseek(outfd, 0, SEEK_CUR)) == (off_t)-1) {
perror("Could not get file position");
exit(5);
}
if (ftruncate(outfd, file_length) == -1) {
perror("Could not truncate file");
exit(6);
}
close(outfd);
exit(0);
}
次のように使用できます。
grep pattern bigfile | overwrite bigfile
私は主に他の人がそれを試す前にコメントできるようにこれを投稿しています。たぶん他の人が似たようなことをして、もっとテストされたプログラムを知っているかもしれません。