Kto ustawia zmienne środowiskowe $ USER i $ USERNAME?

34

Czy te zmienne zawsze będą pasować do aktualnie zalogowanej nazwy użytkownika (robią to w moim systemie Debian)? Czy mogę założyć ich dostępność w innych systemach uniksowych?

Jestem również ciekawy, dlaczego można by użyć whoamizamiast po prostu czytać dowolną z tych zmiennych.

tshepang
źródło
2
Patrząc na manstronę, whoamipodaje nazwę powiązaną z efektywnym identyfikatorem użytkownika. Co oznacza, że ​​zwróci coś innego, jeśli używasz sudolub uruchamiasz plik wykonywalny setuid. Jeśli sudoskonfigurowałeś, spróbuj sudo whoamina przykład.
Joseph R.
4
USERi USERNAMEsą zwykłymi zmiennymi środowiskowymi, co oznacza, że ​​jeśli chcesz, możesz ustawić je na dowolne wartości. Po prostu wpisz USER=xyz. Innymi słowy, nawet jeśli te zmienne istnieją, nie ma gwarancji, że ich wartości odpowiadają aktualnie zalogowanej nazwie użytkownika.
Uwe
@ Uwe By guarantee, miałem na myśli domyślnie (tzn. Zakładając, że użytkownik ich nie zmienił).
tshepang
2
@Tshepang Jako kontynuacja mojego pierwszego komentarza: porównaj wyniki sudo whoamiisudo echo $USER
Joseph R.
2
@JosephR. Ponieważ sudo echo $USERpowłoka rozszerza się $USER, a następnie wywołuje sudo. Więc oczywiście nie daje tego samego wyniku, co whoami. Podobnie sudo whoami, sudo sh -c 'echo $USER'robi (zwykle) wyjście root. Jeśli chodzi o komentarz na temat whoamiużywania identyfikatora EUID , zwróć uwagę, że sudo whoamibyłby generowany, rootnawet gdyby whoamiużywał identyfikatora UID. sudoustawia zarówno identyfikator EUID, jak i identyfikator UID dla uruchomionego polecenia (z wyjątkiem bardzo nietypowej sytuacji, w której jawnie skonfigurowano go, aby zachowywał się inaczej). Porównaj sudo id -uz sudo id -ru.
Eliah Kagan

Odpowiedzi:

29

To login .

Strona podręcznika logowania do systemu Linux (1) mówi:

Wartości dla $ HOME , $ USER , $ SHELL , $ PATH , $ LOGNAME i $ MAIL są ustawiane zgodnie z odpowiednimi polami we wpisie hasła.

Strona podręcznika logowania do FreeBSD (1) mówi:

Logowanie narzędzie wprowadza informacje do środowiska (patrz environ (7) ) określający katalog użytkownika domowego (home), interpretera poleceń (Shell), ścieżka przeszukiwania (PATH), typ terminala (TERM) oraz nazwę użytkownika (zarówno LOGNAME i USER) .

W NetBSD , OpenBSD i OS X strony man powiedzieć to samo.

Oto kod źródłowy z loginu util-linux:

setenv("HOME", pwd->pw_dir, 0); /* legal to override */
setenv("USER", pwd->pw_name, 1);
setenv("SHELL", pwd->pw_shell, 1);
/* ... */
setenv("LOGNAME", pwd->pw_name, 1);

Oto kod źródłowy z loginu FreeBSD:

(void)setenv("LOGNAME", username, 1);
(void)setenv("USER", username, 1);
(void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0);
poige
źródło
2
Na moim pudełku Fedory 16 mam oba USERi USERNAMEustawione, a twoje polecenie tylko zwraca LOGNAME.
Joseph R.
1
@JosephR., Niestety nie mam Fedory pod ręką, ale zajrzałem również do źródeł FreeBSD, patrz UPD ..
poige
Ale oczywiście nie dotyczy to Fedory. Mówię tylko, loginże nie wydaje się być jedyną rzeczą ustawiającą te zmienne.
Joseph R.
1
Zauważ, że Linux jest tylko jądrem, nie ma loginpolecenia. Systemy operacyjne wykorzystujące Linux jako jądro mogą swobodnie korzystać z dowolnej implementacji. Na przykład systemy oparte na Debianie mają tendencję do korzystania z tego z shadow-utils, a nie z ut-linux.
Stéphane Chazelas
1
Należy pamiętać, że loginczęsto nie jest wywoływane podczas logowania się sshprzez większość graficznych menedżerów logowania.
Stéphane Chazelas
11

Nie ma reguły. Niektóre muszle lubią tcshlub zshustawiają $LOGNAME. zshzestawy $USER.

To może być ustawiona przez niektórych rzeczy, które w niczym logowania login(jak wywoływane przez gettyprzy logowaniu na terminal, a czasem przez inne rzeczy, jak in.rlogind) cron, su, sudo, sshd, rshd, graficznych menedżerów logowania lub nie.

Z mojego doświadczenia $USERwynika jednak, że generalnie jest ustawiony (ale może nie zostać zaktualizowany po zmianie identyfikatora użytkownika (za pomocą komend setuid) w ramach tej sesji logowania. POSIX wymaga, aby $LOGNAMEbył ustawiony podczas logowania (i cron).

Aby uzyskać nazwę logowania przenośną, najlepiej użyć lognamepolecenia (jeśli nie było żadnego logowania, może nic nie zwrócić). Aby uzyskać identyfikator użytkownika, użyj id -u. Aby otrzymać jedną nazwę odpowiadającą aktualnej efektywny id użytkownika: id -un. Aby uzyskać je wszystkie (przez większość czasu na identyfikator użytkownika przypada tylko jedna nazwa użytkownika, ale nie jest to gwarantowane):

perl -le 'while ($n = getpwent()) {print $n if getpwnam($n) == $>}'

Chociaż może to nie działać w systemach, w których nie można wyliczyć bazy danych użytkowników (jak to czasami bywa na przykład w sieciowych bazach danych użytkowników).

Stéphane Chazelas
źródło
3

Prawdopodobnie chcesz tutaj polegać na standardzie POSIX , ponieważ w pewnym momencie zapewne będziesz się martwić nie tylko logowaniem użytkownika (zarządzanym przez loginprogram), ale także cronzadaniami i tym podobnymi.

Dlatego powinieneś wiedzieć, że POSIX wymaga, $LOGNAMEale nie wymaga $USER. Np. $USERNie może być ustawiony przez crona, jak wskazano w odpowiedzi Keitha Thompsona , który również odwołuje się do historii, w jaki sposób odnosi się to do historii System-V vs BSD:

... przynajmniej w moim systemie (Ubuntu 14.04) zmienna środowiskowa $ USER nie jest ustawiona dla zadań cron. Zamiast tego możesz użyć $ LOGNAME, który jest częścią środowiska dla zadań cron.

Zgodnie ze stroną podręcznika środowiskowego środowiskowego (7, aby go odczytać, należy wpisać $ USER) w programach pochodnych BSD, a $ LOGNAME w programach pochodnych System-V.

nealmcb
źródło
1

Jeśli chcesz użyć zmiennych środowiskowych (zamiast whoamilub getpwenti getpwnam) i nie masz pewności, czy są one zawsze ustawione w ten sam sposób we wszystkich systemach * NIX, spróbuj tego w bash:

THIS_USER=${USER:-${USERNAME:-${LOGNAME}}}
echo ${THIS_USER}

Jeśli mimo wszystko nadal jest pusty, oznacza to, że jesteś w dość ezoterycznym systemie. ;)

Jesse Chisholm
źródło