Làm cách nào để chia một tệp văn bản lớn thành các tệp nhỏ hơn với số dòng bằng nhau?


515

Tôi đã có một tệp văn bản đơn giản (theo số dòng) lớn mà tôi muốn chia thành các tệp nhỏ hơn, cũng theo số dòng. Vì vậy, nếu tệp của tôi có khoảng 2M dòng, tôi muốn chia nó thành 10 tệp chứa 200k dòng hoặc 100 tệp chứa 20k dòng (cộng với một tệp còn lại; việc chia đều không thành vấn đề).

Tôi có thể làm điều này khá dễ dàng trong Python nhưng tôi tự hỏi liệu có cách ninja nào để làm điều này bằng cách sử dụng các tiện ích bash và unix (trái ngược với các dòng lặp và đếm / phân vùng thủ công).


2
Vì tò mò, sau khi họ "chia tay", làm thế nào để "kết hợp" chúng? Một cái gì đó như "mèo part2 >> part1"? Hoặc có một tiện ích ninja khác? Tâm trí cập nhật câu hỏi của bạn?
dlamotte

7
Để đặt nó trở lại với nhau,cat part* > original
Mark Byers

9
vâng, mèo là viết tắt của concatenate. Nói chung apropos rất hữu ích cho việc tìm kiếm các lệnh thích hợp. IE thấy đầu ra của: apropos split
pixelbeat

@pixelbeat Điều đó thật tuyệt, cảm ơn
danben

3
Bên cạnh đó, người dùng OS X nên đảm bảo rằng tệp của họ chứa các chỉ số ngắt dòng / kết thúc dòng theo kiểu LINUX hoặc UNIX (LF) thay vì MAC OS X - các chỉ báo cuối dòng (CR) - phân tách và Các lệnh csplit sẽ không hoạt động nếu các lần ngắt như của bạn là Trả về vận chuyển thay vì LineFeed. TextWrangler từ phần mềm BareBones có thể giúp bạn điều này nếu bạn đang dùng Mac OS. Bạn có thể chọn cách bạn muốn các ký tự ngắt dòng của bạn trông như thế nào. khi bạn lưu (hoặc Lưu dưới dạng ...) tệp văn bản của bạn.

Câu trả lời:


856

Bạn đã xem lệnh chia?

$ 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

Bạn có thể làm một cái gì đó như thế này:

split -l 200000 filename

sẽ tạo các tệp với 200000 dòng có tên xaa xab xac...

Một tùy chọn khác, được phân chia theo kích thước của tệp đầu ra (vẫn phân chia khi ngắt dòng):

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

tạo các tệp như output_prefix01 output_prefix02 output_prefix03 ...mỗi kích thước tối đa 20 megabyte.


16
bạn cũng có thể chia tệp theo kích thước: split -b 200m filename(m cho megabyte, k cho kilobyte hoặc không có hậu tố cho byte)
Abhi Beckert

136
chia theo kích thước và đảm bảo các tệp được phân chia khi ngắt dòng: tách tên tệp 200m
Clayton Stanley

2
split tạo ra đầu ra bị cắt xén với đầu vào Unicode (UTF-16). Ít nhất là trên Windows với phiên bản tôi có.
Vertigo

4
@geotheory, hãy chắc chắn làm theo lời khuyên của LeberMac trước đó trong chủ đề về kết thúc dòng CR (Mac) đầu tiên thành kết thúc dòng LR (Linux) bằng TextWrangler hoặc BBEdit. Tôi đã có cùng một vấn đề như bạn cho đến khi tôi tìm thấy lời khuyên đó.
sstringer

6
-dtùy chọn không có sẵn trên OSX, sử dụng gsplitthay thế. Hy vọng điều này hữu ích cho người dùng Mac.
dùng5698801


39

Vâng, có một splitlệnh. Nó sẽ phân chia một tập tin theo dòng hoặc byte.

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

Đã dùng thử georgec @ ATGIS25 ~ $ split -l 100000 /cygdrive/P/2012/Job_044_DM_Radio_Propogation/Working/FinalPropogation/TRC_Longlands/trc_longlands.txt
GeorgeC

1
Nó nên ở trong cùng một thư mục. Ví dụ: nếu tôi muốn chia cho 1.000.000 dòng trên mỗi tệp, hãy làm như sau: split -l 1000000 train_file train_file.và trong cùng thư mục tôi sẽ nhận được train_file.aavới một triệu đầu tiên, sau đó trail_file.abvới một triệu tiếp theo, v.v.
Sẽ

1
@GeorgeC và bạn có thể nhận các thư mục đầu ra tùy chỉnh với tiền tố : split input my/dir/.
Ciro Santilli 郝海东 冠状 病 事件

15

sử dụng split

Tách một tệp thành các phần có kích thước cố định, tạo các tệp đầu ra chứa các phần liên tiếp của INPUT (đầu vào tiêu chuẩn nếu không được đưa ra hoặc INPUT là `- ')

Syntax split [options] [INPUT [PREFIX]]

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


13

Sử dụng:

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

Ở đây, 1 và 100 là số dòng mà bạn sẽ nắm bắt được output.txt.


Điều này chỉ thu được 100 dòng đầu tiên, bạn cần lặp nó để liên tiếp chia tệp thành 101..200 tiếp theo, v.v. Hoặc chỉ sử dụng splitnhư tất cả các câu trả lời hàng đầu ở đây đã cho bạn biết.
tripleee

10

chia tệp "file.txt" thành 10000 tệp dòng:

split -l 10000 file.txt

9

split(từ GNU coreutils, kể từ phiên bản 8.8 từ 2010-12-22 ) bao gồm tham số sau:

-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

Do đó, split -n 4 input output.sẽ tạo ra bốn tệp ( output.a{a,b,c,d}) có cùng số byte, nhưng các dòng có thể bị ngắt ở giữa.

Nếu chúng ta muốn bảo toàn các dòng đầy đủ (nghĩa là chia theo các dòng), thì điều này sẽ hoạt động:

split -n l/4 input output.

Câu trả lời liên quan: https://stackoverflow.com/a/19031247


9

Trong trường hợp bạn chỉ muốn chia cho x số dòng mỗi tệp, các câu trả lời đã cho splitlà ổn. Nhưng, tôi tò mò về việc không ai chú ý đến các yêu cầu:

  • "không phải đếm chúng" -> sử dụng wc + cut
  • "có phần còn lại trong tệp bổ sung" -> theo mặc định

Tôi không thể làm điều đó mà không có "wc + cut", nhưng tôi đang sử dụng nó:

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

Điều này có thể dễ dàng được thêm vào các hàm bashrc của bạn để bạn có thể gọi nó đi qua tên tệp và khối:

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

Trong trường hợp bạn muốn chỉ x khối mà không có phần còn lại trong tệp bổ sung, chỉ cần điều chỉnh công thức để tính tổng (chunk - 1) trên mỗi tệp. Tôi sử dụng phương pháp này vì thông thường tôi chỉ muốn x số lượng tệp chứ không phải x dòng trên mỗi tệp:

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

Bạn có thể thêm nó vào một kịch bản và gọi nó là "cách ninja" của bạn, bởi vì nếu không có gì đáp ứng nhu cầu của bạn, bạn có thể xây dựng nó :-)


Hoặc, chỉ cần sử dụng -ntùy chọn split.
Amit N Nikol

8

bạn cũng có thể sử dụng awk

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

3
awk -v lines=200000 -v fmt="%d.txt" '{print>sprintf(fmt,1+int((NR-1)/lines))}'
Đánh dấu Edgar

0

HDFS getmerge tệp nhỏ và tràn vào kích thước tài sản.

Phương pháp này sẽ gây ra ngắt dòng

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

Tôi cố gắng để có được và chia thành khoảng 128 MB mỗi tệp.

# 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}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.