Learner33
Learner33

Reputation: 131

Uniq on array, not displaying correctly

I am new to bash programming and I am struggling with arrays and how to operate with them. SCENARIO:

I have a variable called x which is composed of a group of IP's. This is the output when I echo $x from my script

182.100.67.59 182.100.67.59 182.100.67.59 182.100.67.59 182.100.67.59 182.100.67.59 182.100.67.59 182.100.67.59 182.100.67.59 182.100.67.59 182.100.67.59 182.100.67.59 182.100.67.59 182.100.67.59 182.100.67.59 201.21.24.22 201.21.24.22 201.21.24.22
44.21.25.31 44.21.25.31 44.21.25.31 44.21.25.31
 

Then, I would like to know how many times each IP is repeated. The desired output would be:

15 182.100.67.59
4 44.21.25.31
3 201.21.24.22

I have tried the following

(IFS=" "; sort <<< "$x" ) | uniq -c

Output Note the first 1 on the output.

**1** 182.100.67.59 182.100.67.59 182.100.67.59 182.100.67.59 182.100.67.59 182.100.67.59 182.100.67.59 182.100.67.59 182.100.67.59 182.100.67.59 182.100.67.59 182.100.67.59 182.100.67.59 182.100.67.59 182.100.67.59 201.21.24.22 201.21.24.22 201.21.24.22 44.21.25.31 44.21.25.31 44.21.25.31 44.21.25.31 

I am not seeing this, It should be pretty simple but I can't find the solution :( Thanks! And very great community!

Upvotes: 3

Views: 141

Answers (3)

Vercingatorix
Vercingatorix

Reputation: 1882

Actually you don't have an array, per se; you have a string of numbers separated by spaces. If echo $x gives the value you specify, this is the case and the answer is:

aips=( ${x} )
printf "%s\n" "${aips[@]}"  | sort | uniq -c

This converts the string of numbers separated by spaces (IFS) into the array aips (the parens specify this is an array as opposed to a string), and then uses printf with the behavior that it re-uses the format specification when there are more arguments than the format specification specifies, to print every element of the array (${aips[@]}) followed by a newline, then sorts and uniqs it.

Had this been a real array (e.g. x=( "182.100.67.59" "201.21.24.22" ...)) the answer would be just the latter part:

printf "%s\n" "${x[@]}" | sort | uniq -c

 15 182.100.67.59
  3 201.21.24.22
  4 44.21.25.31

Upvotes: 0

Timur Shtatland
Timur Shtatland

Reputation: 12337

Method 1:
Use tr to replace spaces with newlines, followed by sort | uniq -c:

tr ' ' '\n' <<<"$x" | sort | uniq -c

Method 2:
Use echo with xargs -n1 to write the IPs one per line, followed by sort | uniq -c. Note that xargs is slower than tr here, plus may have potential side effects, such as quote removal:

echo "$x" | xargs -n1 | sort | uniq -c

Upvotes: 3

costaparas
costaparas

Reputation: 5237

There's no need for arrays here.

A simple pipeline using grep, sort and uniq will do the trick:

echo "$x" | grep -Eo '[0-9]+(\.[0-9]+){3}' | sort | uniq -c | sort -rn

Upvotes: 0

Related Questions