Skip to content
VLSI Mentor

Linux & Bash · Part I · Module 13 · Text Processing on the Command Line

Selecting Columns: cut and the Field Separator

The simplest of the field tools, and the one with the clearest edges. It does one job well on strictly delimited data, and it has two limitations that are absolute rather than inconvenient — so most of the value here is in recognising which side of the line your data falls on.

Intermediate16 min readLinuxPart IFundamentalsText Processing

Part I · Module 13 · Chapter 13.2 · Selecting Columns: cut

Chapter 13.1 said a line is a row of fields. This is the tool that takes some of them.

1. Fields

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
$ cat results.csv
test,seed,result,cycles
alu,7,PASS,1200
fifo,9,FAIL,340
cache,3,PASS,98000

$ cut -d, -f1,3 results.csv
test,result
alu,PASS
fifo,FAIL
cache,PASS

-d sets the delimiter, -f chooses the fields. The output keeps the same delimiter between them.

Field lists take ranges:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
cut -d, -f2      results.csv     # field 2
cut -d, -f1,3    results.csv     # fields 1 and 3
cut -d, -f2-4    results.csv     # fields 2 through 4
cut -d, -f3-     results.csv     # field 3 to the end
cut -d, -f-2     results.csv     # the start through field 2

2. Characters Instead of Fields

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
$ echo "abcdefgh" | cut -c2-4
bcd

-c selects by character position rather than by field, with the same range syntax. It is the right tool for genuinely fixed-width data:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
cut -c1-8    timestamps.txt      # the date part of an ISO timestamp
cut -c20-    fixed_width.dat     # everything from column 20

Fixed-width is rarer than it used to be, and it is fragile — one extra character anywhere above shifts every subsequent line. Reach for -c only when the format genuinely guarantees the positions, which usually means it was produced by something old.

(-b selects by byte. For ASCII it is identical to -c; for anything else it will cut a multi-byte character in half. Use -c.)

3. The First Hard Limit: It Cannot Reorder

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
$ cut -d, -f3,1 results.csv
test,result
alu,PASS

Fields 1 and 3, in that order — not 3 then 1.

cut reads the field list as a set, not a sequence. It walks the line once, emitting the fields you asked for in the order they appear. There is no option to change this, and no way to express "field 3, then field 1".

For that you need something that can address fields individually:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
$ awk -F, '{print $3 "," $1}' results.csv
result,test
PASS,alu

4. The Second Hard Limit: One Separator Means One

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
$ printf 'alu    7   PASS\n' > spaced.txt

$ cut -d' ' -f2 spaced.txt

$ awk '{print $2}' spaced.txt
7

cut gave nothing. It split on every single space, so the line is alu, empty, empty, empty, 7, empty, empty, PASS — and field 2 is the first empty one.

awk treats a run of whitespace as one separator, which is what anybody reading aligned columns assumes.

Why column-cutting stops being enough. Cut treats every single separator character as a field boundary, so a run of spaces produces empty fields and the column you asked for is blank. A field-aware tool treats a run of whitespace as one separator, so the same line gives the value you expected.Columns lined up withspacesa run of spaces between eachvalueEvery space is aboundaryso the run makes several emptyfieldsThe field you asked foris blankand nothing reports a problemThe very same linehanded to a field-aware toolinsteadA run of spaces is oneseparatorwhich is what a person readingit assumesYou get the valueand it can reorder the fieldstoo12
Figure 1 — why column-cutting stops being enough. Cut treats every single separator character as a field boundary, so a run of spaces between two values produces several empty fields and the column you asked for turns out to be one of them. A field-aware tool treats a run of whitespace as one separator, so the same line yields the value a person reading it would have expected — and can reorder the fields as well.

Squeezing first

If you must use cut, collapse the runs before it:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
$ tr -s ' ' < spaced.txt | cut -d' ' -f2
7

tr -s squeezes repeated characters into one (Chapter 13.5). It works, and it is two processes where awk is one — but it is occasionally the clearer way to say what you mean, especially when the rest of the pipeline is already cut-shaped.

5. Lines Without the Separator

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
$ printf 'a,b,c\nnoseparator\nd,e,f\n' | cut -d, -f2
b
noseparator
e

A line with no delimiter is passed through whole. cut has nothing to split, so it emits the line unchanged.

That is sometimes convenient and sometimes a silent corruption — a header, a blank line or a footer in the middle of your data arrives in the output looking like a field value.

-s suppresses those lines instead:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
$ printf 'a,b,c\nnoseparator\nd,e,f\n' | cut -d, -f2 -s
b
e

Use -s whenever the data might contain lines that are not records. Tool output with a header banner or a "Total:" footer is exactly that case.

6. The Output Delimiter

GNU cut can change the separator on the way out:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
cut -d, -f1,3 --output-delimiter=' | ' results.csv

This is GNU-only. BSD cut, which is what macOS ships, rejects it:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
$ cut -d, -f1,3 --output-delimiter=' | ' results.csv
cut: illegal option -- -

The portable approaches are tr for a single character, or awk for anything else:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
cut -d, -f1,3 results.csv | tr ',' '\t'              # portable, one character
awk -F, '{print $1 " | " $3}' results.csv            # portable, anything

A useful corollary: cut can only keep the delimiter it was given. Converting a comma-separated file to tab-separated is a tr job, not a cut one.

7. In Practice

Three shapes that come up constantly.

Narrowing a stream mid-pipeline, which is what cut is best at:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
ps -eo pid,user,etime,cmd | grep vcs | cut -c1-60

Pulling one field for a loop:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
cut -d, -f1 -s tests.csv | while IFS= read -r test; do
  ./run_sim.sh "$test"
done

Note -s, so a header line does not become a test name, and the redirect-not-pipe discipline is irrelevant here because nothing inside the loop needs to survive it. (Were it counting, Chapter 12.5 would apply.)

Reading a system file, which is cut's home ground:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
cut -d: -f1 /etc/passwd | sort        # every username
cut -d: -f1,6 /etc/passwd             # username and home directory

/etc/passwd is exactly one colon per field, no alignment, no quoting. This is the data cut was written for.

Practice

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
mkdir -p /tmp/cutd && cd /tmp/cutd
cat > results.csv <<'EOF'
test,seed,result,cycles
alu,7,PASS,1200
fifo,9,FAIL,340
cache,3,PASS,98000
EOF
printf 'alu    7   PASS\nfifo   9   FAIL\n' > spaced.txt
printf 'a\tb\tc\n' > tabbed.txt
printf 'a,b,c\nnoseparator\nd,e,f\n' > mixed.csv

1 — Select fields and ranges.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
cut -d, -f2    results.csv
cut -d, -f1,3  results.csv
cut -d, -f2-4  results.csv
cut -d, -f3-   results.csv

2 — Find the default delimiter.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
cut -f2 tabbed.txt
cut -f2 results.csv

3 — Prove it cannot reorder.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
cut -d, -f3,1 results.csv | head -2
awk -F, '{print $3 "," $1}' results.csv | head -2

4 — Hit the whitespace limit, then work round it.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
cut -d' ' -f2 spaced.txt
awk '{print $2}' spaced.txt
tr -s ' ' < spaced.txt | cut -d' ' -f2

5 — Watch a non-record line pass through.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
cut -d, -f2    mixed.csv
cut -d, -f2 -s mixed.csv

6 — Cut by character.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
echo "2026-10-08T11:02:33" | cut -c1-10
echo "2026-10-08T11:02:33" | cut -c12-

7 — Change the output separator portably.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
cut -d, -f1,3 results.csv | tr ',' '\t'
awk -F, '{print $1 " | " $3}' results.csv

8 — Read a real system file.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
cut -d: -f1 /etc/passwd | head -5
cut -d: -f1,6 /etc/passwd | head -5

9 — Quote a metacharacter delimiter.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
printf 'a|b|c\n' > piped.txt
cut -d'|' -f2 piped.txt

10 — Clean up. cd /tmp && rm -rf /tmp/cutd

Check Your Understanding

1. cut -f2 data.csv returns whole lines. Why?

2. You want fields 3 and 1, in that order. What does cut -d, -f3,1 give you, and what should you use?

3. Why does cut -d' ' -f2 fail on space-aligned output?

4. What does cut do with a line containing no delimiter, and which flag changes it?

5. Give two portable ways to turn comma-separated output into tab-separated.

6. When is cut the better choice than awk?

8. Remember

  • -d sets the delimiter, -f chooses the fields, and ranges like -f2-4 and -f3- work.
  • The default delimiter is a tab. A cut -f2 that returns whole lines is always this.
  • -c selects character positions for genuinely fixed-width data; prefer it to -b.
  • cut cannot reorder fields. -f3,1 gives you 1 then 3, and there is no option for it.
  • That limitation is why it is fast — one pass, no memory. On a large file it is close to the speed of reading.
  • cut splits on every separator, so a run of spaces makes empty fields and aligned columns give nothing.
  • Strictly delimited data: cut. Aligned for a human: awk.
  • tr -s ' ' squeezes runs first if you want to stay with cut.
  • A line with no delimiter passes through whole. -s suppresses those, which matters for headers and footers.
  • --output-delimiter is GNU-only. Use tr or awk to change the separator portably.
  • Quote a delimiter that is a shell metacharacter — -d'|', -d' ', -d$'\t'.

Selecting columns leaves the rows in the order they arrived. The next chapter reorders them — and contains the trap that puts 10 before 2 and makes a summary table quietly wrong.

Where this fits

Part of the Linux & Bash curriculum.