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 getentpolecenia
Użycie getent passwdjest bardziej przenośne niż parsowanie, /etc/passwdponieważ wysyła również zapytania do nielokalnych baz danych NIS lub LDAP.
getent passwd "$uid" | cut -d: -f1
Niestety getentnarzędzie nie wydaje się być określane przez POSIX.
Użyj idpolecenia
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?
getentnie idzwró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/passwdOczywiście poszukuje prac dla zdefiniowanych tam użytkowników).
/etc/passwdi /etc/shadowdo przetestowania tego scenariusza i zweryfikowałem, że oba idi getent passwdzachowują 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_idmogą 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 lsużywa do tłumaczenia identyfikatorów UID na nazwy logowania. Odpowiedź Gillesa jest bardziej bezpośrednim i skutecznym sposobem na osiągnięcie tego.