关于bash:如何将大文本文件拆分成具有相同行数的较小文件?

How to split a large text file into smaller files with equal number of lines?

我有一个大的(按线数)纯文本文件,我想分成较小的文件,也按行数。 因此,如果我的文件有大约2M行,我想将它分成10个包含200k行的文件,或者包含20k行的100个文件(加上一个包含剩余部分的文件;均匀可分的无关紧要)。

我可以在Python中相当容易地做到这一点,但我想知道是否有任何一种使用bash和unix utils的忍者方法(而不是手动循环和计数/分区行)。


你看过split命令了吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ 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   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

你可以这样做:

1
split -l 200000 filename

这将创建每个名为xaa xab xac的200000行的文件...

另一个选项,按输出文件的大小分割(仍然在换行符上拆分):

1
 split -C 20m --numeric-suffixes input_filename output_prefix

创建文件,如output_prefix01 output_prefix02 output_prefix03 ...,每个最大大小为20兆字节。


拆分命令怎么样?

1
split -l 200000 mybigfile.txt


是的,有一个split命令。它将按行或字节拆分文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ 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   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 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.


使用split

Split a file into fixed-size pieces, creates output files containing consecutive sections of INPUT (standard input if none is given or INPUT is `-')

Syntax
split [options] [INPUT [PREFIX]]

http://ss64.com/bash/split.html


使用:

1
sed -n '1,100p' filename > output.txt

这里,1和100是您将在output.txt中捕获的行号。


将文件"file.txt"拆分为10000行文件:

1
split -l 10000 file.txt


split(来自GNU coreutils,自2010-12-22以来的版本8.8)包括以下参数:

1
2
3
4
5
6
7
8
9
-n, --number=CHUNKS     generate CHUNKS output files; see explanation below

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/records
  l/K/N   output Kth of N to stdout without splitting lines/records
  r/N     like 'l' but use round robin distribution
  r/K/N   likewise but only output Kth of N to stdout

因此,split -n 4 input output.将生成具有相同字节数的四个文件(output.a{a,b,c,d}),但中间可能会断行。

如果我们想保留整行(即按行分割),那么这应该有效:

1
split -n l/4 input output.

相关回答:https://stackoverflow.com/a/19031247


如果您只想将每个文件的x行分开,那么关于split的给定答案就可以了。但是,我很好奇没有人关注要求:

  • "无需计算" - >使用wc + cut
  • "将剩余部分放在额外的文件中" - >拆分默认情况下

没有"wc + cut",我不能那样做,但我正在使用它:

1
split -l  $(expr `wc $filename | cut -d ' ' -f3` / $chunks) $filename

这可以很容易地添加到你的bashrc函数中,这样你就可以调用它来传递文件名和块:

1
 split -l  $(expr `wc $1 | cut -d ' ' -f3` / $2) $1

如果您只想在额外文件中使用没有余数的x块,只需调整公式以对每个文件求和(块 - 1)。我确实使用这种方法,因为通常我只需要x个文件而不是每个文件x行:

1
split -l  $(expr `wc $1 | cut -d ' ' -f3` / $2 + `expr $2 - 1`) $1

您可以将其添加到脚本中并将其称为"忍者方式",因为如果没有满足您的需求,您可以构建它:-)


你也可以使用awk

1
awk -vc=1 'NR%200000==0{++c}{print $0 > c".txt"}' largefile


HDFS getmerge小文件并溢出到属性大小。

此方法将导致换行

1
split -b 125m compact.file -d -a 3 compact_prefix

我尝试getmerge并分成每个文件大约128MB。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# split into 128m ,judge sizeunit is M or G ,please test before use.

begainsize=`hdfs dfs -du -s -h /externaldata/$table_name/$date/ | awk '{ print $1}' `
sizeunit=`hdfs dfs -du -s -h /externaldata/$table_name/$date/ | awk '{ print $2}' `
if [ $sizeunit ="G" ];then
    res=$(printf"%.f" `echo"scale=5;$begainsize*8"|bc`)
else
    res=$(printf"%.f" `echo"scale=5;$begainsize/128"|bc`)  # celling ref http://blog.csdn.net/naiveloafer/article/details/8783518
fi
echo $res
# split into $res files with number suffix.  ref  http://blog.csdn.net/microzone/article/details/52839598
compact_file_name=$compact_file"_"
echo"compact_file_name :"$compact_file_name
split -n l/$res $basedir/$compact_file -d -a 3 $basedir/${compact_file_name}