如何对输入文件的部分内容运行命令

如何对输入文件的部分内容运行命令

我有一个大约 40GB 的文件和一个过滤命令,当我尝试在文件上运行它时(即使通过管道传递),该命令由于某种原因会中断。

但是。当我将输入文件拆分成多个小文件、通过过滤器传递每个文件并连接输出时,它不会失败。

因此,我正在寻找一种方法来做:

  • 将文件分割成小块(10MB?)
  • 对每个块运行一些命令
  • 按正确顺序连接输出

但没有先完全分割文件(我不想使用那么多磁盘空间)。

我可以自己编写这样的程序,但也许已经有一些程序可以满足我的需要?

答案1

你不是第一个遇到这个问题的人iconv。有人写过Perl 脚本来解决它。

iconv不能很好地处理大文件。从 glibc 源代码中,在iconv/iconv_prog.c

/* Since we have to deal with
   arbitrary encodings we must read the whole text in a buffer and
   process it in one step.  */

但是,对于您的特定情况,最好编写自己的 UTF-8 验证器。您可以轻松提炼iconv -c -f utf8 -t utf8为一个小的 C 程序,其中包含一个调用的循环iconv(3)由于 UTF-8 是非模式的并且是自同步的,因此您可以分块处理它。

#include <errno.h>
#include <iconv.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define BUFSIZE 4096

/* Copy STDIN to STDOUT, omitting invalid UTF-8 sequences */
int main() {
    char ib[BUFSIZE], ob[BUFSIZE], *ibp, *obp;
    ssize_t bytes_read;
    size_t iblen = 0, oblen;
    unsigned long long total;
    iconv_t cd;

    if ((iconv_t)-1 == (cd = iconv_open("utf8", "utf8"))) {
        perror("iconv_open");
        return 2;
    }

    for (total = 0;
         bytes_read = read(STDIN_FILENO, ib + iblen, sizeof(ib) - iblen);
         total += bytes_read - iblen) {

        if (-1 == bytes_read) {     /* Handle read error */
            perror("read");
            return 1;
        }
        ibp = ib; iblen += bytes_read;
        obp = ob; oblen = sizeof(ob);
        if (-1 == iconv(cd, &ibp, &iblen, &obp, &oblen)) {
            switch (errno) {
              case EILSEQ:          /* Invalid input multibyte sequence */
                fprintf(stderr, "Invalid multibyte sequence at byte %llu\n",
                        1 + total + sizeof(ib) - iblen);
                ibp++; iblen--;     /* Skip the bad byte next time */
                break;
              case EINVAL:          /* Incomplete input multibyte sequence */               
                break;
              default:
                perror("iconv");
                return 2;
            }
        }
        write(STDOUT_FILENO, ob, sizeof(ob) - oblen);

        /* There are iblen bytes at the end of ib that follow an invalid UTF-8
           sequence or are part of an incomplete UTF-8 sequence.  Move them to  
           the beginning of ib. */
        memmove(ib, ibp, iblen);
    }
    return iconv_close(cd);
}

答案2

如果你决定自己写,而且你正在谈论文本文件,那么你可以使用 Perl领带::文件模块。这允许您在大文件上逐行处理。它就是为这种事情而设计的。

你可以尝试领带::文件::任何数据如果该文件不是文本。

答案3

编辑:刚刚注意到你不想因为磁盘空间而提前分割文件,这可能不适合你

使用分割:

$ man split

NAME
   split - split a file into pieces

SYNOPSIS
   split [OPTION] [INPUT [PREFIX]]

DESCRIPTION
   Output fixed-size pieces of INPUT to PREFIXaa, PREFIXab, ...; default size is 1000 lines, and default PREFIX is `x'.  With no INPUT, or when INPUT is -, read standard input.

   Mandatory arguments to long options are mandatory for short options too.

   -a, --suffix-length=N
          use suffixes of length N (default 2)

   -b, --bytes=SIZE
          put SIZE bytes per output file

   -C, --line-bytes=SIZE
          put at most SIZE bytes of lines per output file

   -d, --numeric-suffixes
          use numeric suffixes instead of alphabetic

   -l, --lines=NUMBER
          put NUMBER lines per output file

   --verbose
          print a diagnostic to standard error just before each output file is opened

   --help display this help and exit

   --version
          output version information and exit

   SIZE may have a multiplier suffix: b 512, kB 1000, K 1024, MB 1000*1000, M 1024*1024, GB 1000*1000*1000, G 1024*1024*1024, and so on for T, P, E, Z, Y.

答案4

尝试这个:

/bin/bash #!/bin/bash

文件=/var/log/messages
块大小=100

行=1
总计=`wc -l $FILE | cut -d' '-f1`
当[$LINE -le $TOTAL]时;
  让 ENDLINE=$LINE+$CHUNKSIZE
  sed“${LINE},${ENDLINE}p”$FILE | grep -i“mark”
  让 LINE=$ENDLINE+1
完毕

相关内容