2

Trying to get a unique list of shells on my system. When I run this command:

cat /etc/passwd | cut -d ':' -f 7 | uniq

I get:

/bin/bash  
/bin/sync  
/sbin/shutdown  
/sbin/halt  
/bin/bash

I can't figure out why uniq isn't doing what I want. What don't I understand?

I tried taking this output, making a copy, replacing one of the /bin/bash lines with the other in the copy, and then diffing the files and I got no output, so I'm guessing not a hidden character?

  • The fact that the search "How to get a list of shells" doesn't have an associated question makes me think I could reframe this question "How to get a unique list of shells?" and it wouldn't be a duplicate. What do you think, @ilkkachu? – Brian Peterson Jan 28 '21 at 16:43
  • 1
    The thing about duplicates is not so much in the Question phrasing but the Answering of the core question. The nice thing about duplicates is that they are the many faces of a core issue, all of which are addressed in the linked Q&A. It seems to me that the core issue you faced here is the same "uniq doesn't appear to remove duplicates". – Jeff Schaller Jan 28 '21 at 16:50
  • I found the other question, "How to get a list of shells": https://unix.stackexchange.com/q/140286/40454. So there was no reason to fret. – Brian Peterson Jan 28 '21 at 17:28
  • 2
    getent passwd | awk -F: '{s[$7]++}END{for(i in s)print i, s[i]}' will show the list of shells and how many users are using each. Notice that the user database is NOT always /etc/passwd, so you better use a nss-aware tool like getent. –  Jan 28 '21 at 18:51
  • 1
    @BrianPeterson /etc/shells only lists the shells that a regular user can choose with the chsh tool. The root can set the shell of a user to any program she likes (with chsh or other tool). Notice how that list does not include /bin/sync. –  Jan 28 '21 at 18:55

2 Answers2

8

It's because how uniq works, from the man:

Note: 'uniq' does not detect repeated lines unless they are adjacent. You may want to sort the input first, or use 'sort -u' without 'uniq'.

So, better use, no need of cat:

$ cut -d ':' -f 7 /etc/passwd | sort -u
/bin/bash
/bin/false
/bin/sync
/usr/sbin/nologin

Or, one command

 awk -F: '{ print $7 | "sort -u" }' /etc/passwd

@kojiro's suggestion:

awk -F: '!s[$7]++{print $7}' /etc/passwd
Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
7

You have to pass a sorted output to uniq to make it work.

$ cat /etc/passwd | cut -d ':' -f 7 | sort | uniq
/bin/bash
/bin/sync
/sbin/halt
/sbin/shutdown
Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
annahri
  • 2,075
  • 1
    And if you put the -c option on uniq, it will show you how many people are using each one. – CCTO Jan 28 '21 at 15:32