Pytanie Jak zdobyć katalog $ HOME innego użytkownika w skrypcie Bash?


Muszę wykonać część skryptu bash jako inny użytkownik i wewnątrz tego użytkownika $HOME informator. Jednak nie jestem pewien, jak określić tę zmienną. Przełączam się na tego użytkownika i dzwonię $HOME nie podaje prawidłowej lokalizacji:

# running script as root, but switching to a different user...
su - $different_user
echo $HOME
# returns /root/ but should be /home/myuser

Aktualizacja:

Wygląda na to, że problem polega na tym, że próbuję zmienić użytkowników w moim skrypcie:

$different_user=deploy

# create user
useradd -m -s /bin/bash $different_user

echo "Current user: `whoami`"
# Current user: root

echo "Switching user to $different_user"
# Switching user to deploy

su - $different_user
echo "Current user: `whoami`"
# Current user: root
echo "Current user: `id`"
# Current user: uid=0(root) gid=0(root) groups=0(root)

sudo su $different_user
# Current user: root
# Current user: uid=0(root) gid=0(root) groups=0(root)

Jaki jest prawidłowy sposób przełączania użytkowników i wykonywania poleceń jako inny użytkownik w skrypcie bash?


44
2017-12-10 20:35


pochodzenie


Zawsze możesz wyodrębnić go z / etc / passwd, zakładając, że jest to konto zdefiniowane lokalnie. - Marc B
su - $different_user powinno wystarczyć. Czy na pewno jesteś zalogowany jako myuser. Spróbuj uruchomić id polecenie weryfikacji. Część powłoki logowania jest ustawiona na nologin i kończy się, gdy tylko zalogujesz się jako myuser. - anubhava
@anubhava Zaktualizowałem moje pytanie, aby uwzględnić sposób, w jaki utworzyłem użytkownika. Głównie: useradd -m -s /bin/bash $different_user. - Andrew
Proszę spojrzeć jeszcze raz na moją odpowiedź. Zmieniłem go zasadniczo tak, aby pasował dokładnie do tego, co próbowałeś zrobić. - Michael Kropat


Odpowiedzi:


Aktualizacja: Na podstawie tego pytania, ludzie wydają się tu przychodzić tylko szuka sposobu odnaleźć katalog domowy innego użytkownika, bez potrzeby podszywać się tego użytkownika.

W takim przypadku najprostszym rozwiązaniem jest użycie rozszerzenie tyldy z nazwą użytkownika w połączeniu z eval (co jest potrzebne, ponieważ nazwa użytkownika musi być podana jako niecytowane dosłownie aby rozbudować tyldę):

eval echo "~$different_user"    # prints $different_user's home dir.

Zanotuj zwykły zastrzeżenia dotyczące korzystania z eval zastosować; w tym przypadku zakłada się, że kontrolujesz wartość $different_user i wiem, że to zwykła nazwa użytkownika.

Natomiast pozostała część tej odpowiedzi dotyczy podszywanie się użytkownik i wykonywanie operacji w katalogu domowym tego użytkownika.


Uwaga:

  • Domyślnie administratorzy i inni użytkownicy, którzy uzyskali autoryzację za pośrednictwem sudoers plik może podszywać się pod innych użytkowników za pośrednictwem sudo.
  • Poniższe opiera się na domyślna konfiguracja sudo - zmiana konfiguracji może sprawić, że będzie się zachowywać inaczej - patrz man sudoers.

The podstawowa forma wykonywania polecenia, ponieważ inny użytkownik to:

sudo -H -u someUser someExe [arg1 ...]
  # Example:
sudo -H -u root env  # print the root user's environment

Uwaga:

  • Jeśli zapomnisz podać -H, proces podszywania się (proces wywołany w kontekście określonego użytkownika) zgłosi błąd oryginalny katalog domowy użytkownika w $HOME. 
  • Podszywanie się będzie miało ten sam katalog roboczy, co proces wywoływania.
  • Podlega proces personifikacji bez rozszerzania powłoki na literałach napisanych jako argumenty, ponieważ żadna powłoka nie jest zaangażowana w proces podszywania się (chyba że someExe okazuje się być powłoką) - ekspansje przez powołując się powłoka - przed przejściem do procesu personifikacji - może oczywiście nadal występować.

Opcjonalnie możesz mieć proces podszywania się uruchom jako lub przez powłokę (n podszywanie się), przez prefiksowanie someExe zarówno z -i  lub  -s - nie określając someExe ... tworzy interaktywny muszla:

  • -i tworzy a Zaloguj Się powłoka dla someUser, co implikuje następujące:

    • someUser„s specyficzny dla użytkownika profil powłoki, jeśli jest zdefiniowany, jest ładowany.
    • $HOME punkty dla someUserkatalog domowy, więc jest nie ma potrzeby -H (choć wciąż możesz to określić)
    • Katalog roboczy podszywającej się powłoki to someUserkatalog domowy.
  • -s tworzy powłokę niezalogowaną:

    • bez powłoki profil jest załadowany (chociaż pliki inicjalizacyjne są interaktywne nonlogin muszle są; na przykład., ~/.bashrc)
    • O ile nie określisz również -H, proces podszywania się zgłosi oryginalny katalog domowy użytkownika w $HOME. 
    • Podszywanie się pod powłokę będzie miało ten sam katalog roboczy, co proces wywoływania.

Użycie powłoki oznacza, że ​​argumenty przekazane w wierszu poleceń mogą być podlega ekspansjom powłoki - zobacz poniżej różnice specyficzne dla platformy - przez podszywanie się pod powłokę (prawdopodobnie po początkowym rozszerzeniu przez powłokę wywołującą); porównaj następujące dwa polecenia (które używają pojedynczy cytuje, aby zapobiec przedwczesnemu rozszerzeniu przez powołując się muszla):

  # Run root's shell profile, change to root's home dir.
sudo -u root -i eval 'echo $SHELL - $USER - $HOME - $PWD'
  # Don't run root's shell profile, use current working dir.
  # Note the required -H to define $HOME as root`s home dir.
sudo -u root -H -s eval 'echo $SHELL - $USER - $HOME - $PWD'

Jaka powłoka jest wywoływana jest określana przez "zmienną środowiskową SHELL, jeśli jest ustawiona lub powłoka, jak określono w passwd (5)" (zgodnie z man sudo). Zauważ, że z -s to jest powołując się środowisko użytkownika, które ma znaczenie, podczas gdy z -i to jest podszywany użytkownika.

Zauważ, że są różnice w platformach dotyczące zachowań związanych z powłokami (z -i lub -s):

  • sudo na Linux najwyraźniej akceptuje tylko wykonywalny lub wbudowany nazwa jako pierwszy argument następujący -s/-i, podczas gdy OSX pozwala przekazywać całą linię poleceń powłoki; np. OSX akceptuje sudo -u root -s 'echo $SHELL - $USER - $HOME - $PWD' bezpośrednio (nie ma potrzeby eval), natomiast Linux nie (od sudo 1.8.95p).

  • Starsze wersje sudo w systemie Linux NIE stosuj rozszerzeń powłoki do argumentów przekazywanych do powłoki; na przykład z sudo 1.8.3p1 (np. Ubuntu 12.04), sudo -u root -H -s echo '$HOME' po prostu odtwarza ciąg literalny "$ HOME" zamiast rozszerzać odniesienie do zmiennej w kontekście użytkownika root. Przynajmniej sudo 1.8.9p5 (np. Ubuntu 14.04) zostało to naprawione. Dlatego, aby zapewnić rozszerzenie w systemie Linux, nawet starsze sudo wersje, przekazuj całe polecenie jako pojedynczy argument do eval; na przykład.: sudo -u root -H -s eval 'echo $HOME'. (Chociaż nie jest to konieczne w OSX, to też będzie działać.)

  • The root użytkownika $SHELL zmienna zawiera /bin/sh na OS X 10.9, podczas gdy jest /bin/bash w systemie Ubuntu 12.04.

Niezależnie od tego, czy proces personifikacji obejmuje powłokę, czy nie, w jej środowisku zostaną ustawione następujące zmienne, odzwierciedlające wywołującego użytkownika i polecenie: SUDO_COMMAND, SUDO_USER, SUDO_UID=, SUDO_GID.

Widzieć man sudo i man sudoers dla wielu innych subtelności.

Końcówka czapki dla @DavidW i @Andrew dla inspiracji.


73
2017-12-10 22:41





W BASH możesz znaleźć użytkownika $HOME katalog poprzez prefiksację identyfikatora logowania użytkownika znakiem tyldy. Na przykład:

$ echo ~bob

To będzie echo użytkownika bob„s $HOME informator.

Jednak mówisz, że chcesz móc wykonać skrypt jako konkretny użytkownik. Aby to zrobić, musisz skonfigurować sudo. To polecenie pozwala wykonywać określone polecenia jako konkretny użytkownik. Na przykład, aby wykonać foojako użytkownik bob:

$ sudo -i -ubob -sfoo

Spowoduje to uruchomienie nowej powłoki i -i będzie symulować logowanie z domyślnym środowiskiem użytkownika i powłoką (co oznacza foo polecenie wykona z bob'sKatalog $ HOME`.)

Sudo jest nieco skomplikowane w konfiguracji i musisz być superużytkownikiem, aby móc zobaczyć plik dreszczy (zwykle /etc/sudoers). Jednak ten plik zwykle ma kilka przykładów, których możesz użyć.

W tym pliku można określić polecenia, które można określić, które mogą uruchamiać polecenie, jako który użytkownik i czy użytkownik musi wprowadzić swoje hasło przed wykonaniem tego polecenia. Zwykle jest to ustawienie domyślne (ponieważ udowadnia, że ​​jest to użytkownik, a nie ktoś, do kogo doszło podczas, gdy użytkownik dostawał koksu). Jednak po uruchomieniu skryptu powłoki zazwyczaj trzeba wyłączyć tę funkcję.


20
2017-12-10 21:29



Obiecujący, ale -i i -s wydają się wzajemnie wykluczać. Właśnie -i powinno wystarczyć. - mklement0
Masz problem z przypisaniem ~$different_user do zmiennej i zamieniając ją w $HOME. Czy możesz podać przykład? - Andrew
@Andrew Nie używaj cudzysłowów! user_home=~$different_user. Uwaga: nie ma żadnych cudzysłowów wokół ~$different_user. Twój system operacyjny może również uniemożliwić ponowne przydzielanie HOME ponieważ ma specjalne znaczenie. Czy używasz sudo? To jest zalecany sposób. - David W.


Aby uzyskać alternatywną odpowiedź dla osób poszukujących lekkiego sposobu na znalezienie katalogu domowego użytkownika ...

Zamiast się z tym bawić su hacki lub kłopoty z uruchomieniem innego bash powłoka po prostu znaleźć $HOME Zmienna środowiskowa...

Lekkie proste zapytania Homedir przez Bash

Istnieje specjalne polecenie dla tego: getent

getent passwd someuser | cut -f6 -d:

getent może zrobić o wiele więcej ... po prostu zobacz strona man. The passwd Baza danych nsswitch zwróci wpis użytkownika /etc/passwd format. Po prostu podziel go na dwukropek : by sparsować pola.

Powinien być zainstalowany na większości systemów Linux (lub dowolnego systemu, który używa GNU Lib C (RHEL: glibc-common, Deb: libc-bin)


14
2018-01-29 06:29



getent jest specyficzne dla Linuksa, tak jak to określasz; prostszym i neutralnym dla platformy sposobem jest używanie basha rozszerzenie tyldy z nazwą użytkownika (eval jest potrzebny, ponieważ nazwa użytkownika musi być podana jako niecytowane dosłownie aby rozszerzenie działało): eval echo "~$different_user" - zwykłe zastrzeżenia dotyczące ponownego użycia eval zastosować. - mklement0
Bardzo dobry pomysł, żeby pozwolić bashowi! Inną alternatywą dla bieżącego domu użytkownika jest: eval echo "~$(who -m | awk '{ print $1 }')" lub po prostu eval echo "~". W systemie Mac OS X jest dscl narzędzie, ale jego wynik jest o wiele trudniejszy do przeanalizowania i wymaga już przekazania /Users homedir lub uid (np .: dscl . -read /Users/$(who -m | awk '{ print $1 }')  lub dscl . -search /Users UniqueID $(id -u)). Prawdopodobnie na niektórych platformach po prostu używa się bashu, lub też wykonuję jakieś podstawowe wykrywanie systemu operacyjnego. - TrinitronX
Dla bieżącego użytkownika nie potrzebujesz eval w ogóle: niecytowane ~ zwróci katalog domowy bieżącego użytkownika (np. echo ~). Jeśli naprawdę potrzebujesz nazwy użytkownika bieżącego użytkownika jawnie, $USER jest najprostszy, wydajny i zgodny z POSIX; whoami jest również prosty, ale stosunkowo drogi i nie-POSIX. Twój who -moparte na komendach, a zgodna z POSIX jest jeszcze droższa. Podsumowując: tak, użycie powłoki zgodnej z POSIX (np. Bash) jest najprostsze, najbardziej wydajne i przenośne. - mklement0
getent jest specyficzne dla Linuksa, ale dlaczego? Wydaje się, że jest to najwyraźniej użyteczna rzecz (w zasadzie interfejs wiersza poleceń do przeszukiwania bazy danych, choć zaimplementowany za pomocą plików tekstowych) i powinien również być łatwy do przenoszenia. Cóż, powinien dodatkowo mieć sposób na wyodrębnienie wartości z rekordu. Pozwoli to uniknąć korzystania z ronda cut - David Tonhofer
@DavidTonhofer: Powód getent zamiast tylko czytać /etc/passwd jest ze względu na potencjał dla różnych źródeł zaplecza danych uwierzytelniania użytkownika i logowania. Istnieje wiele baz danych dla bazy danych użytkowników, takich jak sssd(sss / LDAP), NIS i NIS +. Aby uzyskać więcej informacji na ten temat, zobacz to SE Odpowiedź na temat nsswitch.conf. Potrzeba dodatkowego cięcia nie jest najlepsza, z czym bym się zgodziła, ale właśnie to daje narzędzie. Prawdziwy powód użycia getent jest próba wysłania zapytania do skonfigurowanego zaplecza bazy danych użytkownika w systemie. - TrinitronX


Chcesz -u opcja dla sudo w tym przypadku. Od man strona:

The -u (user) option causes sudo to run the specified command as a user other than root.

Jeśli nie musisz go uruchamiać jako ich, możesz przejść do swojego katalogu domowego ~<user>. Tak jak w przypadku, aby przejść do mojego katalogu domowego, możesz użyć cd ~chooban.


3
2017-12-10 20:57



potrzebuję -u opcja z jaką komendą? - Andrew
Czy masz na myśli: sudo -u $different_user su -? - Andrew
@Andrew Nie! Nie rób tego su jako ten inny użytkownik. Użyj polecenia, które chcesz uruchomić jako ten użytkownik. Na przykład, sudo -u $different_user $command - David W.
@DavidW Myślę, że próbowałem znaleźć sposób na uruchomienie wielu poleceń - Andrew
Możesz uruchamiać wiele poleceń za pomocą sudo w jednym skrypcie, jeśli tego potrzebujesz. Używanie sudo i konfiguracja to najlepszy sposób na zrobienie tego. Twoje polecenia mogą być wyświetlane jako użytkownik bez pytania. W przeciwnym razie musisz zalogować się jako ten użytkownik, a to spowoduje uruchomienie nowej powłoki, co oznacza, że ​​musisz ręcznie uruchomić swoje polecenia. Chcesz to zrobić automatycznie. - David W.


Więc chcesz:

  1. wykonać część skryptu bash jako inny użytkownik
  2. zmień katalog $ HOME tego użytkownika

Zainspirowany przez ta odpowiedź, oto dostosowana wersja Twojego skryptu:

#!/usr/bin/env bash

different_user=deploy

useradd -m -s /bin/bash "$different_user"

echo "Current user: $(whoami)"
echo "Current directory: $(pwd)"
echo

echo "Switching user to $different_user"
sudo -u "$different_user" -i /bin/bash - <<-'EOF'
    echo "Current user: $(id)"
    echo "Current directory: $(pwd)"
EOF
echo

echo "Switched back to $(whoami)"

different_user_home="$(eval echo ~"$different_user")"
echo "$different_user home directory: $different_user_home"

Kiedy go uruchomisz, powinieneś uzyskać następujące informacje:

Current user: root
Current directory: /root

Switching user to deploy
Current user: uid=1003(deploy) gid=1003(deploy) groups=1003(deploy)
Current directory: /home/deploy

Switched back to root
deploy home directory: /home/deploy

2
2017-12-10 21:11



Powinieneś użyć #!/usr/bin/env bash jako shebang. - RedX
@RedX Przypuszczam, że jeśli nie jesteś w Linuksie ... - Michael Kropat
Widzieć stackoverflow.com/questions/10376206/preferred-bash-shebang - RedX


Działa to w systemie Linux. Nie wiem, jak zachowuje się w innych * nixes.

  getent passwd "${OTHER_USER}"|cut -d\: -f 6

2
2017-08-19 16:59





Szukałem tego również, ale nie chciałem podszywać się pod użytkownika, aby po prostu uzyskać ścieżkę!

user_path=$(grep $username /etc/passwd|cut -f6 -d":");

Teraz w swoim skrypcie możesz odnieść się do $user_path w większości przypadków będzie /home/username

Zakłada: Poprzednio ustawiłeś $username z wartością zamierzonej nazwy użytkownika. Źródło: http://www.unix.com/shell-programming-and-scripting/171782-cut-fields-etc-passwd-file-into-variables.html


0
2017-12-28 23:18



Plik passwd zawiera tylko lokalnych użytkowników, więc nie będzie działać dla zintegrowanych użytkowników AD / LDAP. zamiast tego powinieneś użyć warstwy abstrakcji dostarczonej przez 'getent' (patrz powyższy przykład) - Saustrup
Fajnie! TIL. :-) Teraz muszę znaleźć ten skrypt ... - Grizly


Szybko i brudno, i przechowywać w zmiennej:

USER=somebody
USER_HOME="$(echo -n $(bash -c "cd ~${USER} && pwd"))"

0
2018-03-05 07:39





Zmagałem się z tym pytaniem, ponieważ szukałem sposobu, aby to zrobić w skrypcie basha dla OS X, stąd nie było mowy o / etc / passwd, a mój skrypt miał być wykonany jako root, więc tworzenie rozwiązań wywołanie eval lub bash -c niebezpieczne, ponieważ umożliwiły one wprowadzenie kodu do zmiennej określającej nazwę użytkownika.

Oto co znalazłem. Jest prosty i nie umieszcza zmiennej w podpowłoce. Jednak wymaga on, aby skrypt był uruchamiany przez root, tak jak sudos na określone konto użytkownika.

Zakładając, że $ SOMEUSER zawiera poprawną nazwę użytkownika:

echo "$(sudo -H -u "$SOMEUSER" -s -- "cd ~ && pwd")"

Mam nadzieję, że to pomoże komuś!


0
2017-09-24 00:14





Jeśli użytkownik nie istnieje, getent zwróci błąd.

Oto mała funkcja powłoki, która nie ignoruje kodu wyjścia getent:

get_home() {
  local result; result="$(getent passwd "$1")" || return
  echo $result | cut -d : -f 6
}

Oto przykład użycia:

da_home="$(get_home missing_user)" || {
  echo 'User does NOT exist!'; exit 1
}

# Now do something with $da_home
echo "Home directory is: '$da_home'"

0
2018-03-31 13:04