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?