如何使用bash将一个大文件分割成多个小文件?

22

我有一个文件,比如叫做all,它有2000行,我希望将其分割成4个小文件,每个小文件包含500行,分别为1~500、501~1000、1001~1500和1501~2000行。

也许,我可以使用以下方法实现:

cat all | head -500 >small1
cat all | tail -1500 | head -500 >small2
cat all | tail -1000 | head -500 >small3
cat all | tail -500 >small4

但这种方法涉及到行号的计算,当行数不是良好数字,或者我们想要将文件分割成太多小文件时(例如:文件all有3241行,并且我们想将其分割为7个文件,每个文件都有463行),可能会导致错误。

有更好的方法吗?

3个回答

39

当您想要拆分一个文件时,请使用 split 命令:

split -l 500 all all

该命令将文件分割成每个文件大约有500行的几个文件。如果要将文件分割成大小相近的4个文件,则可以使用以下命令:

split -l $(( $( wc -l < all ) / 4 + 1 )) all all

2
有趣的是,使用“split -l”始终获得相同数量的文件似乎对我来说是不可能的,即使原始集合中有足够的行数。例如,考虑将5行拆分为4个文件的集合。要求每个文件放置1行将产生5个文件,而不是4个。要求每个文件放置2行将产生3个文件,而不是4个。如果您的“split”版本具有“split -n”,那么这可能是正确的方法。 - Sébastien Piérard
根据 man split 的说明,如果你想要大约相似大小的4个文件 "不分割行/记录",你也可以使用 split -n l/4 - bluu

10

请查看 split 命令,它应该能做到您想要的(甚至更多):

$ split --help
Usage: split [OPTION]... [INPUT [PREFIX]]
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   generate suffixes of length N (default 2)
      --additional-suffix=SUFFIX  append an additional SUFFIX to file names.
  -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[=FROM]  use numeric suffixes instead of alphabetic.
                                   FROM changes the start value (default 0).
  -e, --elide-empty-files  do not generate empty output files with '-n'
      --filter=COMMAND    write to shell COMMAND; file name is $FILE
  -l, --lines=NUMBER      put NUMBER lines per output file
  -n, --number=CHUNKS     generate CHUNKS output files.  See below
  -u, --unbuffered        immediately copy input to output with '-n r/...'
      --verbose           print a diagnostic just before each
                            output file is opened
      --help     display this help and exit
      --version  output version information and exit

SIZE is an integer and optional unit (example: 10M is 10*1024*1024).  Units
are K, M, G, T, P, E, Z, Y (powers of 1024) or KB, MB, ... (powers of 1000).

CHUNKS may be:
N       split into N files based on size of input
K/N     output Kth of N to stdout
l/N     split into N files without splitting lines
l/K/N   output Kth of N to stdout without splitting lines
r/N     like 'l' but use round robin distribution
r/K/N   likewise but only output Kth of N to stdout

4

就像其他人已经提到的那样,您可以使用 split。接受的答案提到的复杂命令替换是不必要的。为了参考,我添加了以下命令,几乎实现了被请求的内容。请注意,当使用 -n 命令行参数指定块数时,使用 split 时,small* 文件中不包含确切的 500 行。

$ seq 2000 > all
$ split -n l/4 --numeric-suffixes=1 --suffix-length=1 all small
$ wc -l small*
 583 small1
 528 small2
 445 small3
 444 small4
2000 total

或者,您可以使用GNU parallel

$ < all parallel -N500 --pipe --cat cp {} small{#}
$ wc -l small*
 500 small1
 500 small2
 500 small3
 500 small4
2000 total

如您所见,这个咒语相当复杂。GNU Parallel 实际上最常用于并行化管道。在我看来,这是一个值得考虑的工具。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接