opscape

Text processing

split

Split a file into pieces by number of lines, by size or into N equal parts.

split [OPTION...] [FILE [PREFIX]]

11 of 11 examples run in Debian 13.7 on 2026-10-31 · coreutils 9.7-3 · manual: split(1)

split cuts a file into consecutive pieces and writes each to its own file, named PREFIX plus a suffix: xaa, xab, xac... by default. You choose how to cut: -l by number of lines, -b by bytes (-b 100M), -C by bytes without breaking lines, or -n into a given number of chunks.

Typical uses are breaking a large CSV or log into parts that another tool can handle, cutting an archive into pieces that fit an upload limit, and spreading work across parallel jobs. The pieces join back together with a plain cat prefix* > file, because the suffixes sort in the order they were written.

Examples

Split by number of lines

seq 1000 > numbers.txt
split -l 300 numbers.txt
wc -l x*
output
 300 xaa
 300 xab
 300 xac
 100 xad
1000 total

Each piece gets 300 lines and the last one gets what is left, 100. With no prefix given, the files are named xaa, xab and so on.

Choose a prefix and numeric suffixes

seq 1000 > numbers.txt
split -l 400 -d -a 3 numbers.txt part.
ls part.*
output
part.000
part.001
part.002

The last argument is the prefix. -d uses numeric suffixes starting at 000, and -a 3 makes them three digits long, which keeps them in order when there are many pieces.

Keep a file extension on the pieces

split -l 5 --additional-suffix=.csv -d data/sales.csv sales-
ls sales-*
output
sales-00.csv
sales-01.csv
sales-02.csv

--additional-suffix=.csv is appended after the generated suffix, so the pieces still open as CSV files.

Split a CSV and repeat the header in each part

tail -n +2 data/sales.csv | split -l 5 -d - part-
for f in part-*; do
  { head -n 1 data/sales.csv; cat "$f"; } > "$f.csv" && rm "$f"
done
head -n 3 part-01.csv
output
date,region,product,units,price
2026-03-03,south,widget,9,4.50
2026-03-04,east,gadget,4,19.99

split knows nothing about headers. Split the data rows (the - reads standard input), then put the header line back in front of each piece.

Split a binary file by size

head -c 2500 /dev/urandom > blob.bin
split -b 1K blob.bin blob.part.
ls -l blob.part.*
output
-rw-r--r-- 1 dev dev 1024 Oct 31 20:20 blob.part.aa
-rw-r--r-- 1 dev dev 1024 Oct 31 20:20 blob.part.ab
-rw-r--r-- 1 dev dev  452 Oct 31 20:20 blob.part.ac

-b 1K cuts every 1024 bytes regardless of content, so the pieces are 1024, 1024 and 452 bytes. Suffixes like K, M and G are powers of 1024.

Put the pieces back together

head -c 5000 /dev/urandom > blob.bin
split -b 2K blob.bin piece.
cat piece.* > restored.bin
cmp blob.bin restored.bin && echo identical
output
identical

The shell expands piece.* in sorted order, which is the order split created them in, so cat restores the original byte for byte; cmp finds no difference.

Split into N parts of similar size

seq 1000 > numbers.txt
split -n 3 -d numbers.txt part-
wc -c part-*
output
1298 part-00
1298 part-01
1297 part-02
3893 total

-n 3 makes exactly three pieces of nearly equal size in bytes. This may cut through the middle of a line.

N parts without breaking lines

seq 1000 > numbers.txt
split -n l/3 numbers.txt part-
wc -l part-*
tail -n 1 part-aa
output
 352 part-aa
 324 part-ab
 324 part-ac
1000 total
352

-n l/3 still aims for three parts of similar byte size but only cuts at line ends. The line counts differ because the early numbers are shorter, and part-aa ends with the complete line 352.

Deal lines out round-robin

split -n r/2 todo.txt worker-
head worker-*
output
==> worker-aa <==
buy milk
write tests
deploy v2.4

==> worker-ab <==
fix login bug
fix logout bug

r/2 hands out lines alternately, like dealing cards: lines 1, 3, 5 go to the first file and 2, 4 to the second. Useful to share a task list between parallel workers.

Limit size without splitting lines

split -C 30 todo.txt piece-
head piece-*
output
==> piece-aa <==
buy milk
fix login bug

==> piece-ab <==
write tests
fix logout bug

==> piece-ac <==
deploy v2.4

-C 30 puts as many whole lines as fit into 30 bytes in each piece. buy milk and fix login bug fit together; adding write tests would exceed the limit.

Compress the pieces on the fly

seq 100000 > numbers.txt
split -l 50000 --filter='gzip > $FILE.gz' numbers.txt part-
ls part-*
output
part-aa.gz
part-ab.gz

With --filter, each piece is piped into a command instead of written directly; $FILE is the name the piece would have had. Single quotes stop your shell from expanding $FILE too early.

Common pitfalls

  • Without a prefix, pieces are called xaa, xab... in the current directory, which is easy to lose or overwrite. Always give a prefix.

  • Two-letter suffixes allow 676 pieces. GNU split extends the suffix automatically when needed, but other implementations stop with an error; set -a when you expect many pieces.

  • -b and -n N cut in the middle of lines; for text use -l, -C or -n l/N.

GNU vs BSD and macOS

The examples above ran the GNU/Linux version. These are the differences that matter on macOS and the BSDs (written from their documentation, not run here).

  • --additional-suffix, --filter and -C are GNU options. BSD/macOS split has -l, -b and -a; support for -d and -n varies by version, so check your system's man page.

Options worth knowing

A selection, described in our own words. For the full list, see split(1) or split --help.

OptionWhat it does
-l, --lines NUMBERPut NUMBER lines in each output file.
-b, --bytes SIZEPut SIZE bytes in each output file; accepts K, M, G suffixes.
-C, --line-bytes SIZEPut at most SIZE bytes of whole lines in each file.
-n, --number CHUNKSSplit into CHUNKS files: N, l/N (whole lines), r/N (round-robin).
-a, --suffix-length NUse suffixes of length N (2 by default).
-dUse numeric suffixes starting at 0 instead of letters.
--numeric-suffixes[=FROM]Like -d, optionally starting at FROM.
-xUse hexadecimal suffixes instead of letters.
--additional-suffix SUFFIXAppend SUFFIX, such as .csv, to every file name.
--filter COMMANDPipe each piece into COMMAND; $FILE holds the piece's name.
-e, --elide-empty-filesDo not create empty files with -n.
--verbosePrint a line for each file created.

Related