GNU/Linux >> Tutoriales Linux >  >> Linux

Manera de modificar un archivo en el lugar?

Tengo un archivo bastante grande (35 Gb) y me gustaría filtrar este archivo in situ (es decir, no tengo suficiente espacio en disco para otro archivo), específicamente quiero grep e ignorar algunos patrones. ¿Hay alguna manera de hacer esto sin usar otro archivo?

Digamos que quiero filtrar todas las líneas que contienen foo: por ejemplo…

Respuesta aceptada:

En el nivel de llamada al sistema esto debería ser posible. Un programa puede abrir su archivo de destino para escribir sin truncarlo y comenzar a escribir lo que lee desde la entrada estándar. Al leer EOF, el archivo de salida se puede truncar.

Dado que está filtrando líneas desde la entrada, la posición de escritura del archivo de salida siempre debe ser menor que la posición de lectura. Esto significa que no debe corromper su entrada con la nueva salida.

Sin embargo, encontrar un programa que haga esto es el problema. dd(1) tiene la opción conv=notrunc que no trunca el archivo de salida al abrirlo, pero tampoco lo hace al final, dejando el contenido del archivo original después del contenido de grep (con un comando como grep pattern bigfile | dd of=bigfile conv=notrunc )

Dado que es muy simple desde la perspectiva de una llamada al sistema, escribí un pequeño programa y lo probé en un sistema de archivos de bucle invertido completo pequeño (1MiB). Hizo lo que quería, pero realmente quiere probar esto con otros archivos primero. Siempre será arriesgado sobrescribir un archivo.

sobrescribir.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 usarías como:

grep pattern bigfile | overwrite bigfile

Principalmente estoy publicando esto para que otros comenten antes de intentarlo. Tal vez alguien más conozca un programa que haga algo similar que esté más probado.

Relacionado:¿Quién es el propietario del archivo si el archivo se crea con el comando sudo?
Linux
  1. ¿Manera portátil de obtener el tamaño del archivo (en bytes) en Shell?

  2. forma más rápida de convertir archivos delimitados por tabulaciones a csv en linux

  3. La forma más eficiente de copiar un archivo en Linux

  4. ¿Hay alguna forma de editar un marcador de nautilus (administrador de archivos) existente?

  5. ¿Hay alguna forma de cambiar los atajos en el comandante de medianoche?

Una manera fácil de ocultar archivos y directorios en Linux

Manera fácil de fusionar archivos con el comando Cat

¿Agregar archivo ejecutable al menú de Lubuntu?

¿Hay alguna manera de reanudar un scp interrumpido de un archivo?

cp -L frente a cp -H

¿Hay una forma adecuada de borrar los registros?