CrackOps
Interview PrepTracksLinuxAWS LabSoonInterview RoomSoon
Sign inStart free
CrackOps

Interview prep for the people who keep production up.

[email protected]
ProductInterview PrepTracksDashboardInterview Room
RolesDevOpsSREPlatformCloud
CompanyAboutContactPrivacyTerms
© CrackOps
Linux / Text Processing / uniq

uniq

Collapse and count repeated adjacent lines

Beginnerpipelinescountinglogs

uniq collapses runs of identical adjacent lines into one, and with -c it counts them. Put sort in front and it becomes a group-by: sort | uniq -c | sort -rn is the most famous pipeline in log analysis.

Syntaxuniq [OPTION]... [INPUT [OUTPUT]]

Watch it run

There were 164 failed logins (HTTP 401). Is one client brute-forcing the login endpoint?

devops@devops-lab: ~/logs — zsh — 96×28
➜ ~/logs
Step 1 of 2
awk '$9 == 401 {print $1}' access.log | uniq -c | head -5

Every count is 1. The failures from one IP are spread through the log with other IPs in between, and uniq only merges identical lines that are next to each other.

Anatomy of a command

$ | | |
commandawk '{print $1}' access.log

Extract the key you want to count, one per line: here the client IP.

How it works

uniq reads its input line by line and keeps exactly one previous line in memory. For each new line it compares with the previous one: if equal, it increments a counter; if different, it prints the previous line (with the count for -c) and starts a new run. That's why it uses constant memory on any size of input, and also why it cannot find duplicates that aren't next to each other: it never looks further back than one line. sort solves that by making all equal lines adjacent, at the cost of reading everything first. Options change what 'equal' means: -i ignores case, -f N skips the first N fields, -s N skips N characters and -w N compares only the first N characters. -d prints only lines that were repeated, -u only those that never were. If the input is already grouped, like a log in time order, you can skip the sort.

Five processes connected by pipes run at the same time; sort is the one step that must read everything before it can write.

read()pipepipepipepipewrite()access.log23,994 linesawkprint $1sortgroup equal IPsuniq -ccount each runsort -rnrank by counthead -3first 3 linesTerminal3 lines
1/8
One line, five processes

The shell creates four pipes and starts all five commands at once. Each process's stdout is wired to the next one's stdin; none of them knows about the others.

5Processes4Pipes
← → to step

Options you'll actually use

-cPrefix each line with the number of times it occurred in a row
-dOnly print lines that were repeated (one copy each)
-uOnly print lines that were never repeated
-iIgnore case when comparing
-f NSkip the first N fields when comparing (e.g. a timestamp)
-s NSkip the first N characters when comparing
-w NCompare only the first N characters
-DPrint every copy of the repeated lines (GNU)

Common mistakes

uniq -c access_ips.txt on unsorted input

uniq only merges adjacent duplicates, so the counts are split across many runs and mostly 1.

sort access_ips.txt | uniq -c
grep ERROR app.log | sort | uniq -c (every count is 1)

Each line has a unique timestamp and request ID, so no two lines are identical. Remove the varying parts before counting.

grep ERROR app.log | cut -d' ' -f2- | sed 's/req=[^ ]* //' | sort | uniq -c
sort | uniq -c | sort -n | head for the top items

Ascending order puts the rarest lines first, so head shows the bottom of the list.

sort | uniq -c | sort -rn | head
uniq input.txt input.txt to dedupe in place

The second argument is the OUTPUT file. uniq opens it for writing, truncating the input before it has been read.

sort -u -o input.txt input.txt

Interview questions

Practice

Try these on a Linux machine of your own. Each task has a hint and a solution.

  1. 1

    Count how many times each log level (the 2nd field) appears in ~/logs/app.log, most frequent first.

  2. 2

    Print only the lines that appear more than once in ~/data/hosts.txt.

  3. 3

    Count the distinct login shells in /etc/passwd and how many users use each.

  4. 4

    Show how many requests per minute were logged in the last 5 minutes of ~/logs/app.log.

Related commands

sortSort lines: alphabetically, numerically, by columnawkProcess text by columns: filter, sum, count and reportcutCut columns or character ranges out of each linegrepSearch text for lines that match a pattern
PrevioussortNexttr
Linux / Text Processing / uniq

uniq

Collapse and count repeated adjacent lines

Beginnerpipelinescountinglogs

uniq collapses runs of identical adjacent lines into one, and with -c it counts them. Put sort in front and it becomes a group-by: sort | uniq -c | sort -rn is the most famous pipeline in log analysis.

Syntaxuniq [OPTION]... [INPUT [OUTPUT]]

Watch it run

There were 164 failed logins (HTTP 401). Is one client brute-forcing the login endpoint?

devops@devops-lab: ~/logs — zsh — 96×28
➜ ~/logs
Step 1 of 2
awk '$9 == 401 {print $1}' access.log | uniq -c | head -5

Every count is 1. The failures from one IP are spread through the log with other IPs in between, and uniq only merges identical lines that are next to each other.

Anatomy of a command

$ | | |
commandawk '{print $1}' access.log

Extract the key you want to count, one per line: here the client IP.

How it works

uniq reads its input line by line and keeps exactly one previous line in memory. For each new line it compares with the previous one: if equal, it increments a counter; if different, it prints the previous line (with the count for -c) and starts a new run. That's why it uses constant memory on any size of input, and also why it cannot find duplicates that aren't next to each other: it never looks further back than one line. sort solves that by making all equal lines adjacent, at the cost of reading everything first. Options change what 'equal' means: -i ignores case, -f N skips the first N fields, -s N skips N characters and -w N compares only the first N characters. -d prints only lines that were repeated, -u only those that never were. If the input is already grouped, like a log in time order, you can skip the sort.

Five processes connected by pipes run at the same time; sort is the one step that must read everything before it can write.

read()pipepipepipepipewrite()access.log23,994 linesawkprint $1sortgroup equal IPsuniq -ccount each runsort -rnrank by counthead -3first 3 linesTerminal3 lines
1/8
One line, five processes

The shell creates four pipes and starts all five commands at once. Each process's stdout is wired to the next one's stdin; none of them knows about the others.

5Processes4Pipes
← → to step

Options you'll actually use

-cPrefix each line with the number of times it occurred in a row
-dOnly print lines that were repeated (one copy each)
-uOnly print lines that were never repeated
-iIgnore case when comparing
-f NSkip the first N fields when comparing (e.g. a timestamp)
-s NSkip the first N characters when comparing
-w NCompare only the first N characters
-DPrint every copy of the repeated lines (GNU)

Common mistakes

uniq -c access_ips.txt on unsorted input

uniq only merges adjacent duplicates, so the counts are split across many runs and mostly 1.

sort access_ips.txt | uniq -c
grep ERROR app.log | sort | uniq -c (every count is 1)

Each line has a unique timestamp and request ID, so no two lines are identical. Remove the varying parts before counting.

grep ERROR app.log | cut -d' ' -f2- | sed 's/req=[^ ]* //' | sort | uniq -c
sort | uniq -c | sort -n | head for the top items

Ascending order puts the rarest lines first, so head shows the bottom of the list.

sort | uniq -c | sort -rn | head
uniq input.txt input.txt to dedupe in place

The second argument is the OUTPUT file. uniq opens it for writing, truncating the input before it has been read.

sort -u -o input.txt input.txt

Interview questions

Practice

Try these on a Linux machine of your own. Each task has a hint and a solution.

  1. 1

    Count how many times each log level (the 2nd field) appears in ~/logs/app.log, most frequent first.

  2. 2

    Print only the lines that appear more than once in ~/data/hosts.txt.

  3. 3

    Count the distinct login shells in /etc/passwd and how many users use each.

  4. 4

    Show how many requests per minute were logged in the last 5 minutes of ~/logs/app.log.

Related commands

sortSort lines: alphabetically, numerically, by columnawkProcess text by columns: filter, sum, count and reportcutCut columns or character ranges out of each linegrepSearch text for lines that match a pattern
PrevioussortNexttr