cut pulls columns out of each line of text. You can select by field with a delimiter, by character position, or by byte. It’s fast and simple, and perfect for structured files like /etc/passwd and CSV exports.
Fields with a delimiter
cut -d: -f1 /etc/passwd # usernames
cut -d: -f1,7 /etc/passwd # username and shell
cut -d, -f2 users.csv # second CSV column
cut -d, -f2-4 users.csv # columns 2 to 4
cut -d, -f3- users.csv # column 3 to the end
cut -d' ' -f1 access.log # first space-separated field (client IP)
-dsets the delimiter (one character; default is tab).-fselects fields:1,1,3,2-4,3-,-2.
Change the output delimiter:
cut -d: -f1,7 --output-delimiter=' -> ' /etc/passwd
# root -> /bin/bash
Characters and bytes
cut -c1-8 file # first 8 characters of each line
cut -c10- file # from character 10 onwards
echo "2026-10-14T09:12:00" | cut -c1-10 # 2026-10-14
cut -b1-4 file # bytes (differs from -c for multibyte text)
Character ranges are useful for fixed-width output, such as dates at a known position in log lines.
Everything except some fields
cut -d, -f2 --complement data.csv # drop column 2
Lines without the delimiter
By default, lines that don’t contain the delimiter are printed unchanged. Use -s to skip them:
cut -d: -f2 -s file
Practical examples
Users with a login shell:
grep -v -E 'nologin|false' /etc/passwd | cut -d: -f1
Top client IPs (combined with sort and uniq):
cut -d' ' -f1 /var/log/nginx/access.log | sort | uniq -c | sort -rn | head
Just the version number:
nginx -v 2>&1 | cut -d/ -f2 # 1.26.2
The value from KEY=value lines:
grep '^DB_HOST=' .env | cut -d= -f2-
-f2- matters here. Values that themselves contain = (base64 strings, URLs) keep everything after the first =.
Hostnames from URLs:
cut -d/ -f3 urls.txt
The big limitation: repeated spaces
cut -d' ' treats each space as a delimiter. Output aligned with several spaces, such as ps, df, ls -l and free, produces empty fields and the wrong columns:
df -h | cut -d' ' -f5 # unreliable
Use awk, which splits on runs of whitespace:
df -h | awk '{print $5}'
Or squeeze the spaces first: df -h | tr -s ' ' | cut -d' ' -f5. See awk and tr.
CSV with quoted fields
cut -d, doesn’t understand quotes, so "Smith, John",42 splits in the wrong place. For real CSV, use a CSV-aware tool: csvcut (from csvkit), mlr (Miller), or python3 -c with the csv module.
cut vs awk
| Need | Tool |
|---|---|
| Single-character delimiter, simple fields | cut |
| Whitespace-aligned columns | awk |
Reorder fields (3,1) |
awk (cut always prints in input order) |
| Conditions, maths, formatting | awk |
| Character positions | cut -c |
Note that cut -f3,1 prints field 1 then field 3. It never reorders.
Quick reference
| Task | Command |
|---|---|
Field N, delimiter : |
cut -d: -fN |
| Several fields | cut -d, -f1,3 |
| Range | cut -d, -f2-4 |
| From N to end | cut -d= -f2- |
| Characters | cut -c1-10 |
| All except field | cut -d, -f2 --complement |
| Skip lines without delimiter | cut -s |