Przetwórz plik / etc / passwd, aby wyświetlić listę wszystkich użytkowników, których folder domowy znajduje się w / home

10

Mam przykładowy plik / etc / passwd, taki jak ten:

tom:x:1000:1000:Work:/home/tom:/bin/bash
george:x:1000:1000:Work:/home/george:/bin/bash
bla:x:1000:1000:Work:/home/bla:/bin/bash
boo:x:1000:1000:Work:/home/boo:/bin/bash
bee:x:1000:1000:Work:/root/list:/bin/bash

Próbuję wyświetlić listę wszystkich użytkowników z folderem domowym /home/.

napisałem

cat ~/Desktop/e.txt |awk -F ":" '{if ($6 ~/^/home/) print $1;}'

gdzie e.txt to tekst, który tutaj skopiowałem.

Rozumiem, że występuje problem z odwrotnym ukośnikiem, który jest znakiem ucieczki, ale jak to naprawić, aby móc wymienić je w jednym wierszu polecenia?

erans
źródło
11
Ogólna rada oprócz odpowiedzi (które pojawiają się w odstępie zaledwie jednej sekundy!): Prawie nigdy nie ma sensu catprzesyłać do narzędzi takich jak awklub sedpodobnych, ponieważ można podać nazwę pliku jako argument.
Philippos,
1
cat e.txt | grep home | cut -d ":" -f 1
Arpit Agarwal
3
Ponieważ wszyscy użytkownicy mają UID o wartości 1000 rzeczy, może to być trochę trudne.
StrongBad
1
@ArpitAgarwal grep home e.txt | cut -d ":" -f 1. Gratulujemy nagrody UUOC. Nie jest to jednak dobre rozwiązanie. Co się stanie, jeśli istnieje usługa „homebackups”, która działa pod osobnym użytkownikiem nazwanym na cześć demona? To fałszywie pozytywny wynik.
NieDzejkob
2
@Philippos re „Prawie nigdy nie ma sensu przesuwać narzędzia do kota i potoku [że] można podać nazwę pliku jako argument” - generalnie używam cat > toolwariantu takich linii poleceń, ponieważ można poprawić przejrzystość, utrzymując przepływ od lewej do prawej wejściowego przetwarzania wyjściowego łańcucha rurowego. To jest mniej wydajny, ale prawie zawsze minimalnie tak. To również sprawia, że dodanie paska postępu w stosownych przypadkach i użyteczne, gdy uruchomiony interaktywnie bardzo oczywiste (wystarczy wymienić catze pvjeśli jest zainstalowany).
David Spillett,

Odpowiedzi:

11

Możesz uciec przed ukośnikami, jak pokazano poniżej:

awk -F':' '$6~/^\/home\//{ print $1 }' ~/Desktop/e.txt

Inną sztuczką byłoby użycie złożonego separatora pól:

awk -F'[:/]' '$7=="home"{ print $1 }' ~/Desktop/e.txt
  • -F'[:/]'- traktować oba :i /być separatorem pól
Roman Perekhrest
źródło
2
Uważam, że pole komentarza (bezpośrednio przed katalogiem domowym) może zawierać ukośnik.
12

Możesz użyć cudzysłowów zamiast /wyrażenia regularnego, aby uniknąć ucieczki przed /:

awk -F: '$6 ~ "^/home/" {print $1}' ~/Desktop/e.txt

Z awk, {if (foo) ... }często można uprościć tylko foo {...}.

muru
źródło
8

Zakładając, że e.txtjest w rzeczywistości /etc/passwd, należy faktycznie używać getent passwdzamiast parsowania pliku, ponieważ informacja o kontach użytkowników mogą być przechowywane w wielu miejscach określonych w /etc/nsswitch.conftakich jak LDAP.

getent passwd | awk -F ':' '$6 ~ "^/home"'

Zauważ, że printinstrukcja jest implikowana, gdy warunek jest spełniony. To jednak wydrukuje całą linię. Spowoduje to wydrukowanie tylko nazwy użytkownika:

getent passwd | awk -F ':' '$6 ~ "^/home" {print $1}'
Wstrzymano do odwołania.
źródło
4

Alternatywa dla tych z nas, którzy po prostu nie lubią awk:

grep -E '^([^:]*:){5}/home/' ~/Desktop/e.txt | cut -d: -f1

Wyjaśnienie:

  • grep -E umożliwia korzystanie z kilku rozszerzonych funkcji wyrażeń regularnych
  • Wyrażenie ([^:]*:)pasuje do jednej kolumny, w tym do następującego separatora „:”
  • ^([^:]*:){5} dopasowuje pierwsze pięć kolumn każdej linii
  • ^([^:]*:){5}/home/ dopasowuje każdy wiersz, w którym szósta kolumna zaczyna się od „/ home /”
  • cut -d: -f1wybiera tylko pierwszą kolumnę danych wejściowych, używając :jako separatora kolumn
rosarote elfe
źródło
3

Możesz także użyć indexdo poprawienia dopasowania ciągów podobnych grep -Fi użyć wartości zwracanej, aby upewnić się, że pasuje do początku łańcucha

$ awk -F: 'index($6,"/home/")==1{print $1}' ip.txt
tom
george
bla
boo

lub jeśli potrzebne jest wyrażenie regularne, przekaż je jako zmienną środowiskową

$ r='^/home/' awk -F: '$6 ~ ENVIRON["r"]{print $1}' ip.txt
tom
george
bla
boo
Sundeep
źródło
3

Tylko dla odmiany

$ perl -F: -lane 'print $F[0] if m(/home/)' e.txt
tom
george
bla
boo

Wyjaśnienie

-F:     use ":" as field separator  
-lane
    l   add newline line-ending to every print statement
    a   auto-split input lines into @F array
    n   apply expression line by line to named file (or STDIN)
    e   evaluate perl commands given on command line

print $F[0]   print (only) the first field of each line
if m(/home/)  but only if the line contains the text /home/

Odmiana, jeśli chcesz być wybredny, jeśli /home/chodzi o miejsce znalezienia

perl -F: -lane 'print $F[0] if $F[5] =~ m(^/home/)' e.txt
RedGrittyBrick
źródło