opscape

Text processing

cut

Print selected fields, characters or bytes from each line, such as columns of a CSV or TSV file.

cut -f LIST [-d DELIM] [FILE...] | cut -c LIST [FILE...] | cut -b LIST [FILE...]

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

cut extracts parts of every line. It works in one of three modes: -f selects fields separated by a single delimiter character (tab by default, any other with -d), -c selects character positions and -b selects byte positions. A list can be single numbers, ranges and open ranges: -f 1,3, -f 2-4, -f 3-.

cut is fast and simple, and that simplicity is its main limitation. The delimiter is exactly one character, and every occurrence counts, so text aligned with several spaces produces empty fields. Fields always come out in their original order, whatever order you list them in. When you need to split on runs of whitespace, reorder columns or compute anything, use awk instead; for proper CSV with quoted commas, use a CSV-aware tool.

Examples

Select columns of a CSV

cut -d , -f 2,4 data/users.csv | head -n 4
explain
output
name,dept
Alice Moreau,engineering
Bob Okafor,sales
Chen Wei,engineering

-d , makes the comma the delimiter and -f 2,4 keeps the second and fourth fields, name and department.

Tab is the default delimiter

cut -f 2 data/inventory.tsv
explain
output
qty
12
3
5

Without -d, cut splits on tabs, which is exactly what a TSV file uses, so -f 2 gives the quantity column.

A range of fields to the end of the line

cut -d , -f 3- data/sales.csv | head -n 3
explain
output
product,units,price
widget,12,4.50
gadget,3,19.99

3- means from field 3 to the last one; -3 would mean fields 1 to 3.

Fixed character positions

cut -c 1-10 logs/app.log | sort -u
explain
output
2026-03-14

-c 1-10 keeps the first ten characters of every line, which in this log is the date. sort -u shows that all entries are from the same day.

Pick fields from a space-separated log

cut -d ' ' -f 1,7 access.log | head -n 4
explain
output
192.0.2.10 /
192.0.2.10 /static/app.css
198.51.100.7 /login
198.51.100.7 /login

Splitting the access log on single spaces makes the client IP field 1 and the request path field 7 (the quoted method "GET is field 6).

Everything except some fields

cut -d , --complement -f 3 data/users.csv | head -n 3
explain
output
id,name,dept,joined
1,Alice Moreau,engineering,2021-04-12
2,Bob Okafor,sales,2019-11-03

--complement inverts the selection, dropping the email column and keeping the rest.

Change the delimiter in the output

cut -d , -f 1,3 --output-delimiter=$'\t' data/users.csv | head -n 3
explain
output
id	email
1	alice@example.com
2	bob@example.com

--output-delimiter joins the selected fields with a different string, here a tab, turning CSV into TSV for the selected columns.

Fields of a system file

cut -d : -f 1,7 /etc/passwd | head -n 4
explain
output
root:/bin/bash
daemon:/usr/sbin/nologin
bin:/usr/sbin/nologin
sys:/usr/sbin/nologin

/etc/passwd is colon-separated; fields 1 and 7 are the user name and login shell.

Trap: field order cannot be changed

cut -d , -f 3,1 data/users.csv | head -n 2
explain
output
id,email
1,alice@example.com

Asking for 3,1 still prints field 1 before field 3: cut always outputs fields in the order they appear in the line. To swap columns use awk -F, -v OFS=, '{print $3, $1}'.

Trap: several spaces mean empty fields

echo 'alpha   beta' | cut -d ' ' -f 2
echo 'alpha   beta' | awk '{print $2}'
output

beta

Each of the three spaces is a delimiter, so field 2 is the empty string between the first two, and cut prints an empty line. awk splits on runs of whitespace and prints beta. Squeezing spaces first with tr -s ' ' also works.

Lines without the delimiter are printed whole

printf 'name,qty\n# comment line\nwidget,12\n' | cut -d , -f 2
echo ---
printf 'name,qty\n# comment line\nwidget,12\n' | cut -s -d , -f 2
output
qty
# comment line
12
---
qty
12

A line that contains no delimiter at all is passed through unchanged, so the comment shows up in the first output. -s suppresses such lines.

Trap: -c counts bytes in GNU cut

echo 'café' | cut -c 1-4 | od -c
explain
output
0000000   c   a   f 303  \n
0000005

GNU cut -c currently behaves like -b and counts bytes. é is two bytes in UTF-8, so positions 1 to 4 keep only its first byte (octal 303), an invalid fragment. Use awk with substr() or cut only on ASCII text when positions matter.

The delimiter must be one character

cut -d ', ' -f 1 data/users.csv
explain
outputexit 1
cut: the delimiter must be a single character
Try 'cut --help' for more information.

cut refuses multi-character delimiters. Split on , and strip spaces separately, or use awk -F ', '.

Common pitfalls

  • cut -d ' ' on text aligned with multiple spaces returns empty fields. Use awk '{print $2}' or squeeze first: tr -s ' ' | cut -d ' ' -f 2.

  • cut -f 3,1 does not reorder; output is always in input order. Use awk to reorder columns.

  • Quoted CSV fields such as "Smith, Jane" are split at the inner comma. cut knows nothing about quoting.

  • A line without the delimiter is printed in full in -f mode. Add -s to skip headers, comments or blank lines that lack it.

  • Command output that looks tab-separated is often padded with spaces (ps, df, ls -l). Check with cat -A, and prefer awk for such output.

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

  • --complement and --output-delimiter are GNU-only. BSD/macOS cut has -b, -c, -f, -d, -s and -n.

  • BSD/macOS cut -c counts characters in a UTF-8 locale; GNU cut -c counts bytes like -b.

Options worth knowing

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

OptionWhat it does
-f, --fields LISTSelect these fields, for example 1,3 or 2-4 or 3-.
-d, --delimiter CHARUse CHAR as the field delimiter instead of tab.
-c, --characters LISTSelect these character positions (bytes in GNU cut).
-b, --bytes LISTSelect these byte positions.
-s, --only-delimitedSkip lines that contain no delimiter.
--complementPrint everything except the selected fields, characters or bytes.
--output-delimiter STRINGJoin selected fields with STRING instead of the input delimiter.
-z, --zero-terminatedLines end with NUL instead of newline.
-nIgnored by GNU cut; on BSD, do not split multi-byte characters with -b.

Related