Często chcę uzyskać nazwę logowania powiązaną z identyfikatorem użytkownika, a ponieważ okazało się, że jest to częsty przypadek użycia, postanowiłem napisać funkcję powłoki, aby to zrobić. Chociaż głównie używam dystrybucji GNU / Linux, staram się pisać skrypty, aby były jak najbardziej przenośne i sprawdzać, czy to, co robię, jest zgodne z POSIX.
Analizować /etc/passwd
Pierwsze podejście, które próbowałem, to parsowanie /etc/passwd
(używanie awk
).
awk -v uid="$uid" -F: '$3 == uid {print $1}' /etc/passwd
Jednak problem z tym podejściem polega na tym, że logowanie może nie być lokalne, np. Uwierzytelnianie użytkownika może odbywać się przez NIS lub LDAP.
Użyj getent
polecenia
Użycie getent passwd
jest bardziej przenośne niż parsowanie, /etc/passwd
ponieważ wysyła również zapytania do nielokalnych baz danych NIS lub LDAP.
getent passwd "$uid" | cut -d: -f1
Niestety getent
narzędzie nie wydaje się być określane przez POSIX.
Użyj id
polecenia
id
jest standardowym narzędziem POSIX do uzyskiwania danych o tożsamości użytkownika.
Implementacje BSD i GNU akceptują identyfikator użytkownika jako operand:
- id (1) - strony podręcznika OpenBSD
- id (1) - strona podręcznika FreeBSD
- GNU Coreutils: wywołanie identyfikatora
Oznacza to, że można go użyć do wydrukowania nazwy logowania powiązanej z identyfikatorem użytkownika:
id -nu "$uid"
Jednak podanie ID użytkownika jako argumentu operacji nie jest określone w POSIX; opisuje tylko użycie nazwy logowania jako operandu.
Łącząc wszystkie powyższe
Rozważałem połączenie powyższych trzech podejść w coś takiego:
get_username(){
uid="$1"
# First try using getent
getent passwd "$uid" | cut -d: -f1 ||
# Next try using the UID as an operand to id.
id -nu "$uid" ||
# As a last resort, parse `/etc/passwd`.
awk -v uid="$uid" -F: '$3 == uid {print $1}' /etc/passwd
}
Jest to jednak niezgrabne, nieeleganckie i - co ważniejsze - nietrwałe; kończy działanie ze statusem niezerowym, jeśli identyfikator użytkownika jest nieprawidłowy lub nie istnieje. Zanim napisałem dłuższy i bardziej niezgrabny skrypt powłoki, który analizuje i przechowuje status wyjścia każdego wywołania polecenia, pomyślałem, że zapytam tutaj:
Czy istnieje bardziej elegancki i przenośny (zgodny z POSIX) sposób uzyskiwania nazwy logowania powiązanej z identyfikatorem użytkownika?
getent
nie id
zwróci niczego po pierwszym dopasowaniu; jedynym sposobem na znalezienie ich wszystkich jest wyliczenie wszystkich użytkowników, jeśli baza danych użytkowników na to pozwala. ( /etc/passwd
Oczywiście poszukuje prac dla zdefiniowanych tam użytkowników).
/etc/passwd
i /etc/shadow
do przetestowania tego scenariusza i zweryfikowałem, że oba id
i getent passwd
zachowują się jak opisano. Jeśli w pewnym momencie skończę z systemem, w którym użytkownik ma wiele nazw, zrobię to samo co te narzędzia systemowe i po prostu traktuję pierwsze wystąpienie jako kanoniczną nazwę tego użytkownika.
setuid(some_id)
i nie ma wymagań, które some_id
mogą być częścią bazy danych użytkowników. Przy takich rzeczach, jak przestrzenie nazw użytkowników w systemie Linux, może to okazać się paraliżującym założeniem dla twoich skryptów.
getpwuid()
funkcji, która ls
używa do tłumaczenia identyfikatorów UID na nazwy logowania. Odpowiedź Gillesa jest bardziej bezpośrednim i skutecznym sposobem na osiągnięcie tego.