GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Möglichkeit, eine Datei direkt zu ändern?

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?
Linux
  1. Tragbarer Weg, um die Dateigröße (in Bytes) in der Shell zu erhalten?

  2. Die effizienteste Methode zum Kopieren einer Datei unter Linux

  3. So ändern Sie die Kernel-DTB-Datei

  4. Wie ändere ich eine Datei direkt mit awk? (wie bei sed -i)

  5. Gibt es eine richtige Möglichkeit, Protokolle zu löschen?

Einfache Möglichkeit, Dateien mit dem Cat-Befehl zusammenzuführen

Ausführbare Datei zum Lubuntu-Menü hinzufügen?

Gibt es eine Möglichkeit, ein unterbrochenes scp einer Datei fortzusetzen?

Gibt es eine Möglichkeit, Shortcuts in Midnight Commander zu ändern?

cp-L vs. cp-H

Der sicherste Weg, um das Schließen eines Dateideskriptors zu erzwingen