GNU/Linux >> Znalost Linux >  >> Linux

Jak upravit soubor na místě?

Mám poměrně velký soubor (35 Gb) a chtěl bych tento soubor filtrovat in situ (tj. nemám dostatek místa na disku pro jiný soubor), konkrétně chci grep a ignorovat některé vzory — existuje způsob, jak udělat to bez použití jiného souboru?

Řekněme, že chci odfiltrovat všechny řádky obsahující foo: například…

Přijatá odpověď:

Na úrovni systémového volání by to mělo být možné. Program může otevřít váš cílový soubor pro zápis, aniž by jej zkrátil, a začít zapisovat to, co čte ze stdin. Při čtení EOF může být výstupní soubor zkrácen.

Protože filtrujete řádky ze vstupu, pozice pro zápis výstupního souboru by měla být vždy menší než pozice pro čtení. To znamená, že byste neměli poškodit svůj vstup novým výstupem.

Najít program, který to dělá, je však problém. dd(1) má možnost conv=notrunc která nezkrátí výstupní soubor při otevření, ale také se nezkrátí na konci, takže původní obsah souboru zůstane po obsahu grep (pomocí příkazu jako grep pattern bigfile | dd of=bigfile conv=notrunc )

Protože je to z pohledu systémového volání velmi jednoduché, napsal jsem malý program a otestoval ho na malém (1MiB) souborovém systému s plnou smyčkou. Dělalo to, co jste chtěli, ale opravdu to chcete nejprve otestovat s jinými soubory. Přepsání souboru bude vždy riskantní.

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);
}

Použili byste jej jako:

grep pattern bigfile | overwrite bigfile

Většinou to posílám pro ostatní, aby se k tomu vyjádřili, než to vyzkoušíte. Možná někdo jiný ví o programu, který dělá něco podobného, ​​který je více testován.

Související:Kdo je vlastníkem souboru, pokud je soubor vytvořen pomocí příkazu sudo?
Linux
  1. Chytrý způsob, jak defragmentovat tlustý souborový systém?

  2. nejrychlejší způsob převodu souboru odděleného tabulátory na csv v linuxu

  3. Nejúčinnější způsob kopírování souboru v Linuxu

  1. Existuje způsob, jak upravit existující záložku nautilus (správce souborů)?

  2. Automatické verzování při změně souboru (upravit/vytvořit/smazat)

  3. Existuje způsob, jak obnovit přerušený scp souboru?

  1. Existuje způsob, jak změnit zkratky v půlnočním veliteli?

  2. Nejbezpečnější způsob, jak vynutit uzavření deskriptoru souboru

  3. Existuje správný způsob, jak vymazat protokoly?