如何运行input文件的部分命令

我有〜40GB的文件和一个filter命令,当我尝试在文件上运行时(即使通过pipe道传递),出于某种原因中断了。

但。 当我把input文件分割成许多小文件,通过filter传递每个文件,并连接输出时,它并不会失败。

所以,我正在寻找一个办法:

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

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

我可以自己编写这样的程序,但也许已经有东西可以做我需要的东西了?

你不是第一个用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-8validation器可能会更好。 你可以很容易地将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); } 

如果你决定自己写,而你正在谈论文本文件,你可以使用Perl :: Tie :: File模块。 这使您可以在适当的时间处理大文件。 这是为了这样的事情。

如果文件不是文本,你可以试试Tie :: File :: AnyData 。

编辑:只是注意到你不想提前分割文件,因为磁盘空间,这可能不会为你工作

使用分割:

 $ 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. 

我build议使用sed来提取你想要的部分,并将输出pipe道输送到你的命令中:

 sed -n '1,1000p' yourfile | yourcommand 

将pipe道前1000行到您的命令

 sed -n '1001,2000p' yourfile | yourcommand 

将pipe下一千条线。

等等

如果你愿意的话,你可以把它放在脚本的循环中。

例如

 #!/bin/bash size=1000 lines=`cat $1 | wc -l` first=1 last=$size while [ $last -lt $lines ] ; do sed -n "${first},${last}p" $1 | yourcommand first=`expr $last + 1` last=`expr $last + $size` done last=$lines sed -n "${first},${last}p" $1 | yourcommand 

尝试这个:

 #!/斌/庆典

 FILE =的/ var /日志/消息
 CHUNKSIZE = 100

 LINE = 1
 TOTAL =`wc -l $ FILE | 剪下-d“'-f1'
而[$ LINE -le $ TOTAL]; 做
  让ENDLINE = $ LINE + $ CHUNKSIZE
   sed“$ {LINE},$ {ENDLINE} p”$ FILE |  grep -i“mark”
  让LINE = $ ENDLINE + 1
 DONE

那么 – 每个人都build议写我自己的解决scheme。 我可以。 而且我甚至可以不用多次input文件的“扫描”。 但问题是:有没有现成的工具?

最简单的基于Perl的方法可能如下所示:

 #!/usr/bin/perl -w use strict; my ( $lines, $command ) = @ARGV; open my $out, '|-', $command; my $i = 0; while (<STDIN>) { $i++; if ($i > $lines) { close $out; open $out, '|-', $command; $i = 1; } print $out $_; } close $out; exit; 

现在我可以:

 => seq 1 5 1 2 3 4 5 => seq 1 5 | ./run_in_parts.pl 3 tac 3 2 1 5 4