Text processing
split
Split a file into pieces by number of lines, by size or into N equal parts.
split [OPTION...] [FILE [PREFIX]]
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*
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.*
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-*
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
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.*
-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
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-*
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
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-*
==> 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-*
==> 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-*
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
splitextends the suffix automatically when needed, but other implementations stop with an error; set-awhen you expect many pieces.-band-n Ncut in the middle of lines; for text use-l,-Cor-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,--filterand-Care GNU options. BSD/macOSsplithas-l,-band-a; support for-dand-nvaries 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.
| Option | What it does |
|---|---|
-l, --lines NUMBER | Put NUMBER lines in each output file. |
-b, --bytes SIZE | Put SIZE bytes in each output file; accepts K, M, G suffixes. |
-C, --line-bytes SIZE | Put at most SIZE bytes of whole lines in each file. |
-n, --number CHUNKS | Split into CHUNKS files: N, l/N (whole lines), r/N (round-robin). |
-a, --suffix-length N | Use suffixes of length N (2 by default). |
-d | Use numeric suffixes starting at 0 instead of letters. |
--numeric-suffixes[=FROM] | Like -d, optionally starting at FROM. |
-x | Use hexadecimal suffixes instead of letters. |
--additional-suffix SUFFIX | Append SUFFIX, such as .csv, to every file name. |
--filter COMMAND | Pipe each piece into COMMAND; $FILE holds the piece's name. |
-e, --elide-empty-files | Do not create empty files with -n. |
--verbose | Print a line for each file created. |
Related
catConcatenate files and print them to standard output; also the quickest way to see a short file.headPrint the first lines (or bytes) of files; 10 lines by default.tailPrint the last lines of files, or follow a file as it grows with -f.cmpCompare two files byte by byte and report the first difference, or just whether they differ.gzipCompress files to .gz (replacing the original by default), or decompress them with -d or gunzip.