GNU/Linux >> Linux Esercitazione >  >> Linux

Modo per modificare un file sul posto?

Ho un file abbastanza grande (35 Gb) e vorrei filtrare questo file in situ (cioè non ho abbastanza spazio su disco per un altro file), in particolare voglio grep e ignorare alcuni schemi - c'è un modo per farlo senza usare un altro file?

Diciamo che voglio filtrare tutte le righe che contengono foo: per esempio...

Risposta accettata:

A livello di chiamata di sistema ciò dovrebbe essere possibile. Un programma può aprire il file di destinazione per la scrittura senza troncarlo e iniziare a scrivere ciò che legge da stdin. Durante la lettura di EOF, il file di output può essere troncato.

Poiché stai filtrando le righe dall'input, la posizione di scrittura del file di output dovrebbe essere sempre inferiore alla posizione di lettura. Ciò significa che non dovresti corrompere il tuo input con il nuovo output.

Tuttavia, trovare un programma che fa questo è il problema. dd(1) ha l'opzione conv=notrunc che non tronca il file di output all'apertura, ma non tronca anche alla fine, lasciando il contenuto del file originale dopo il contenuto di grep (con un comando come grep pattern bigfile | dd of=bigfile conv=notrunc )

Dal momento che è molto semplice dal punto di vista della chiamata di sistema, ho scritto un piccolo programma e l'ho testato su un piccolo filesystem di loopback completo (1MiB). Ha fatto quello che volevi, ma vuoi prima provarlo con alcuni altri file. Sarà sempre rischioso sovrascrivere un file.

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

Lo useresti come:

grep pattern bigfile | overwrite bigfile

Sto principalmente pubblicando questo per consentire ad altri di commentare prima di provarlo. Forse qualcun altro sa di un programma che fa qualcosa di simile che è più testato.

Correlati:chi è il proprietario del file se il file viene creato utilizzando il comando sudo?
Linux
  1. Un modo semplice per nascondere file e directory in Linux

  2. Un modo intelligente per deframmentare un file system grasso?

  3. Qual è il modo corretto di usare inotify?

  4. C'è un modo per ritagliare un file NETCDF?

  5. Come ordinare un file sul posto

Un modo semplice per unire i file con il comando Cat

Aggiungere un file eseguibile al menu di Lubuntu?

Il modo più efficiente per copiare un file in Linux

Come modificare il file DTB del kernel

C'è un modo per riprendere uno scp interrotto di un file?

cp -L contro cp -H