Text-Processing

有沒有辦法就地修改文件?

  • May 9, 2021

我有一個相當大的文件(35Gb),我想就地過濾這個文件(即我沒有足夠的磁碟空間來存放另一個文件),特別是我想 grep 並忽略一些模式 - 有沒有辦法在不使用其他文件的情況下執行此操作?

假設我想過濾掉所有包含foo:例如…的行

在系統呼叫級別,這應該是可能的。程序可以打開您的目標文件進行寫入而不截斷它,並開始寫入它從標準輸入讀取的內容。讀取 EOF 時,可以截斷輸出文件。

由於您要從輸入中過濾行,因此輸出文件的寫入位置應始終小於讀取位置。這意味著你不應該用新的輸出破壞你的輸入。

但是,找到一個可以做到這一點的程序是問題所在。dd(1)具有conv=notrunc在打開時不截斷輸出文件的選項,但它也不會在最後截斷,將原始文件內容留在 grep 內容之後(使用類似的命令grep pattern bigfile | dd of=bigfile conv=notrunc

由於從系統呼叫的角度來看它非常簡單,因此我編寫了一個小程序並在一個小型 (1MiB) 完整環回文件系統上對其進行了測試。它做了你想要的,但你真的想先用其他一些文件來測試它。覆蓋文件總是有風險的。

覆蓋.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);
}

您可以將其用作:

grep pattern bigfile | overwrite bigfile

在您嘗試之前,我主要發布此內容以供其他人評論。也許其他人知道有一個程序可以做類似的事情,但經過更多的測試。

引用自:https://unix.stackexchange.com/questions/11067