Ich habe eine ziemlich große Datei (35 GB) und möchte diese Datei in situ filtern (d. H. Ich habe nicht genügend Speicherplatz für eine andere Datei), insbesondere möchte ich einige Muster grep und ignorieren - gibt es eine Möglichkeit dazu tun dies, ohne eine andere Datei zu verwenden?
Nehmen wir an, ich möchte alle Zeilen herausfiltern, die foo:
enthalten zum Beispiel…
Akzeptierte Antwort:
Auf Systemaufrufebene sollte dies möglich sein. Ein Programm kann Ihre Zieldatei zum Schreiben öffnen, ohne sie abzuschneiden, und mit dem Schreiben beginnen, was es von stdin liest. Beim Lesen von EOF kann die Ausgabedatei abgeschnitten werden.
Da Sie Zeilen aus der Eingabe filtern, sollte die Schreibposition der Ausgabedatei immer kleiner sein als die Leseposition. Das bedeutet, dass Sie Ihre Eingabe nicht mit der neuen Ausgabe verfälschen sollten.
Das Problem ist jedoch, ein Programm zu finden, das dies tut. dd(1)
hat die Option conv=notrunc
Das schneidet die Ausgabedatei beim Öffnen nicht ab, aber es schneidet auch nicht am Ende ab und hinterlässt den ursprünglichen Dateiinhalt nach dem grep-Inhalt (mit einem Befehl wie grep pattern bigfile | dd of=bigfile conv=notrunc
)
Da es aus Sicht des Systemaufrufs sehr einfach ist, habe ich ein kleines Programm geschrieben und es auf einem kleinen (1 MiB) vollständigen Loopback-Dateisystem getestet. Es hat getan, was Sie wollten, aber Sie möchten dies wirklich zuerst mit einigen anderen Dateien testen. Es ist immer riskant, eine Datei zu überschreiben.
overwrite.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);
}
Sie würden es verwenden als:
grep pattern bigfile | overwrite bigfile
Ich poste dies hauptsächlich, damit andere es kommentieren können, bevor Sie es versuchen. Vielleicht kennt jemand anderes ein Programm, das etwas Ähnliches tut, das besser getestet ist.
Verwandte:Wer ist der Dateibesitzer, wenn die Datei mit dem Befehl sudo erstellt wird?