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?

Brian Peterson
  • 619
  • 1
  • 7
  • 12
  • 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
  • 66,199
  • 35
  • 114
  • 250
schrodingerscatcuriosity
  • 12,087
  • 3
  • 29
  • 57
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
  • 66,199
  • 35
  • 114
  • 250
annahri
  • 2,030
  • 14
  • 32
  • 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