web-dev-qa-db-fra.com

Comment obtenir le répertoire $ HOME de différents utilisateurs dans un script bash?

Je dois exécuter une partie d'un script bash en tant qu'utilisateur différent et dans le répertoire $HOME de cet utilisateur. Cependant, je ne sais pas comment déterminer cette variable. Passer à cet utilisateur et appeler $HOME ne fournit pas le bon emplacement:

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

Mettre à jour:

Il semble que le problème réside dans la façon dont j'essaie de changer d'utilisateur dans mon script:

$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)

Quelle est la bonne façon de changer d'utilisateur et d'exécuter des commandes en tant qu'utilisateur différent dans un script bash?

50
Andrew

Update: d'après le titre de cette question, les gens semblent venir ici cherchent simplement un moyen de trouver le répertoire de base d'un utilisateur différent, sans qu'il soit nécessaire de imiter utilisateur

Dans ce cas, la solution la plus simple consiste à utiliser tilde expansion avec le nom d'utilisateur qui vous intéresse, associé à eval (nécessaire, car le nom d'utilisateur doit être donné sous la forme d'un littéral non entre guillemets pour que l’extension tilde fonctionne):

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

Remarque: Les mises en garde habituelles relatives à l'utilisation de eval apply; dans ce cas, on suppose que vous contrôlez la valeur de $different_user et que vous savez qu'il s'agit d'un simple nom d'utilisateur.

En revanche, le reste de cette réponse concerne imitation d'identité un utilisateur et effectuant des opérations dans le répertoire de base de cet utilisateur.


Remarque:

  • Les administrateurs par défaut et les autres utilisateurs, s'ils sont autorisés via le fichier sudoers, peuvent emprunter l'identité d'autres utilisateurs via Sudo.
  • Ce qui suit est basé sur la configuration par défaut de Sudo - le fait de changer de configuration peut entraîner un comportement différent - voir man sudoers.

La forme basic permettant d’exécuter une commande en tant qu’autre utilisateur est:

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

Remarque:

  • Si vous oubliez de spécifier -H, le processus d'emprunt d'identité (processus appelé dans le contexte de l'utilisateur spécifié) signalera le répertoire de base de l'utilisateur original dans $HOME. 
  • Le processus d'emprunt d'identité aura le même répertoire de travail que le processus d'appel.
  • Le processus d'emprunt d'identité exécute no des extensions Shell sur les littéraux de chaîne transmis en tant qu'arguments, car aucun Shell n'est impliqué dans le processus d'emprunt d'identité (sauf si someExe se trouve être un shell) - extensions par le invoquant Shell - avant passer au processus de personnification - peut évidemment encore se produire.

Vous pouvez éventuellement exécuter un processus d'usurpation d'identité en tant que ou via un shell, en préfixant someExe soit avec -isoit-s - en ne spécifiant pas someExe ..., vous créez un shell interactif:

  • -i crée un shell login pour someUser, ce qui implique les éléments suivants:

    • someUser 's le profil Shell spécifique à l'utilisateur, s'il est défini, est chargé.
    • $HOME pointe vers le répertoire de base de someUser, donc aucun besoin de -H (bien que vous puissiez le spécifier)
    • Le répertoire de travail de l’emprunt d’identité Shell est le répertoire de base de la someUser
  • -s crée un shell sans connexion:

    • aucun shell profil n'est chargé (bien que les fichiers d'initialisation pour les shells interactifs non-connexion soient; par exemple, ~/.bashrc)
    • Sauf si vous spécifiez également -H, le processus d'emprunt d'identité indiquera le répertoire de base de l'utilisateur {original} _ dans $HOME. 
    • Le Shell utilisant l'identité du client aura le même répertoire de travail que le processus d'appel.

L'utilisation d'un shell signifie que les arguments de chaîne passés sur la ligne de commande PEUVENT être sujets aux extensions du shell - voir différences spécifiques à la plate-forme ci-dessous - par le shell imitant (éventuellement après le développement initial par le shell appelant) ; comparez les deux commandes suivantes (qui utilisent unique guillemets pour empêcher un développement prématuré par le shell {invoquant}:

  # 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'

Quel Shell est appelé est déterminé par "la variable d'environnement Shell si elle est définie ou par le shell spécifié dans passwd (5)" (selon man Sudo). Notez qu'avec -s c'est l'environnement de l'utilisateur invoquant qui compte, alors qu'avec -i c'est l'utilisateur imité.

Notez qu'il existe des différences de plate-forme en ce qui concerne le comportement lié au shell (avec -i ou -s):

  • Sudo SOUS LINUX N'ACCEPTE APPAREMMENT QUE LE NOM EXÉCUTABLE OU INTÉGRÉ COMME ARGUMENT PREMIER SUIVANT LE -s/-i, alors que OSX permet de passer toute la ligne de commande de Shell; Par exemple, OSX accepte Sudo -u root -s 'echo $Shell - $USER - $HOME - $PWD' directement (pas besoin de eval), contrairement à Linux (à partir de Sudo 1.8.95p).

  • Les anciennes versions de Sudo sur Linux n'appliquent PAS les extensions Shell aux arguments transmis à un Shell; Par exemple, avec Sudo 1.8.3p1 (Ubuntu 12.04, par exemple), Sudo -u root -H -s echo '$HOME' renvoie simplement le littéral de chaîne "$ HOME" au lieu de développer la référence de variable dans le contexte de l'utilisateur racine. À partir d’au moins Sudo 1.8.9p5 (Ubuntu 14.04, par exemple), cela a été corrigé. Par conséquent, pour garantir une expansion sur Linux même avec les versions Sudo antérieures, transmettez la commande entière sous la forme d'un argument unique à eval; Exemple: Sudo -u root -H -s eval 'echo $HOME'. (Bien que cela ne soit pas nécessaire sous OSX, cela fonctionnera aussi.)

  • La variable $Shell de l'utilisateur root contient /bin/sh sous OSX 10.9, alors qu'il s'agit de /bin/bash sous Ubuntu 12.04.

Que le processus d'emprunt d'identité implique un shell ou non, son environnement aura les variables suivantes définies, reflétant l'utilisateur et la commande appelants: Sudo_COMMAND, Sudo_USER, Sudo_UID=, Sudo_GID.

Voir man Sudo et man sudoers pour beaucoup plus de subtilités.

Coup de chapeau à @DavidW et @Andrew pour trouver l'inspiration.

82
mklement0

Dans BASH, vous pouvez rechercher le répertoire $HOME d'un utilisateur en préfixant son identifiant de connexion par un tilde. Par exemple:

$ echo ~bob

Cela fera écho dans le répertoire $HOME de l'utilisateur bob.

Cependant, vous dites que vous voulez pouvoir exécuter un script en tant qu'utilisateur particulier. Pour ce faire, vous devez configurer Sudo . Cette commande vous permet d'exécuter des commandes particulières en tant qu'utilisateur particulier. Par exemple, pour exécuter foo en tant qu'utilisateur bob:

$ Sudo -i -ubob -sfoo

Cela démarrera un nouveau shell et le -i simulera une connexion avec l'environnement par défaut de l'utilisateur et le shell (ce qui signifie que la commande foo sera exécutée à partir du répertoire bob's $ HOME`.)

Sudo est un peu complexe à configurer et vous devez être superutilisateur pour pouvoir voir le fichier shudders (généralement /etc/sudoers). Cependant, ce fichier contient généralement plusieurs exemples que vous pouvez utiliser.

Dans ce fichier, vous pouvez spécifier les commandes que vous spécifiez, qui peut exécuter une commande, quel utilisateur, et si cet utilisateur doit ou non entrer son mot de passe avant d'exécuter cette commande. Il s’agit normalement de la valeur par défaut (car cela prouve que c’est bien cet utilisateur et non une personne qui l’a récupéré alors qu’il recevait un Coca-Cola). Toutefois, lorsque vous exécutez un script Shell, vous souhaitez généralement désactiver cette fonctionnalité.

21
David W.

Par souci d'une réponse alternative pour ceux qui recherchent un moyen léger de simplement trouver le répertoire d'accueil d'un utilisateur ...

Plutôt que de jouer avec les hacks su, ou de vous ennuyer avec le temps système nécessaire au lancement d'un autre shell bash pour trouver la variable d'environnement $HOME ...

Requête Homedir Simple Léger via Bash

Il existe une commande spécifique pour cela: getent

getent passwd someuser | cut -f6 -d:

getent peut faire beaucoup plus ... consultez la page de manuel . La base de données passwd nsswitch renverra l'entrée de l'utilisateur au format /etc/passwd. Il suffit de le scinder sur le colon : pour analyser les champs.

Il devrait être installé sur la plupart des systèmes Linux (ou sur tout système utilisant GNU Lib C (RHEL: glibc-common, Deb: libc-bin).

15
TrinitronX

Vous voulez l'option -u pour Sudo dans ce cas. De la page man:

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

Si vous n'avez pas besoin de l'exécuter en tant que tel, vous pouvez passer à leur répertoire personnel avec ~<user>. En tant que, pour aller dans mon répertoire personnel, vous utiliseriez cd ~chooban.

3
chooban

Cela fonctionne sous Linux. Je ne sais pas comment cela se comporte dans d'autres * nix. 

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

Donc vous voulez:

  1. exécuter une partie d'un script bash en tant qu'utilisateur différent
  2. passer au répertoire $ HOME de cet utilisateur

Inspiré par cette réponse , voici la version adaptée de votre script:

#!/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"

Lorsque vous l'exécutez, vous devriez obtenir ce qui suit:

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
Michael Kropat

La sortie de getent passwd username peut être analysée avec une expression régulière Bash

OTHER_HOME="$(
  [[ "$(
    getent \
    passwd \
    "${OTHER_USER}"
  )" =~ ([^:]*:){5}([^:]+) ]] \
  && echo "${BASH_REMATCH[2]}"
)"
0
Léa Gris

Si l'utilisateur n'existe pas, getent renverra une erreur.

Voici une petite fonction Shell qui n'ignore pas le code de sortie de getent:

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

Voici un exemple d'utilisation:

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
Elifarley

Le titre de cette question est Comment obtenir le répertoire $ HOME de différents utilisateurs en script bash? et c’est ce que les gens viennent ici de Google pour le découvrir.

Si vous faites cela parce que vous exécutez quelque chose comme root, vous pouvez utiliser la puissance de Sudo:

user=pi
user_home=$(Sudo -u $user sh -c 'echo $HOME')

Sinon, vous pouvez l'obtenir à partir de /etc/passwd. Il existe déjà de nombreux exemples d'utilisation de eval et getent, je vais donc vous donner une autre option:

user=pi
user_home=$(awk -v FS=':' '$1=="'$u'"{print $6}' /etc/passwd)

Je ne voudrais vraiment utiliser celui-là que si j'avais un script bash avec beaucoup d'autres awk oneliners et aucune utilisation de cut. Tandis que beaucoup de gens aiment "coder le golf" pour utiliser le moins de caractères possible pour accomplir une tâche, je préfère "l'outil de golf" car utiliser moins d'outils confère à votre script une "empreinte de compatibilité" plus petite. De plus, votre collègue ou futur collaborateur a moins de pages de manuel à lire pour en comprendre le sens.

0
Bruno Bronosky

Je me débattais avec cette question parce que je cherchais un moyen de faire cela dans un script bash pour OS X. Par conséquent,/etc/passwd était hors de question, et mon script était destiné à être exécuté en tant que root, apportant ainsi les solutions invoquer eval ou bash -c dangerous car ils autorisaient l'injection de code dans la variable spécifiant le nom d'utilisateur. 

Voici ce que j'ai trouvé. C'est simple et ne met pas de variable dans un sous-shell. Cependant, le script doit être exécuté par la racine car il se trouve alors dans le compte d'utilisateur spécifié.

En supposant que $ SOMEUSER contienne un nom d'utilisateur valide:

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

J'espère que cela aide quelqu'un!

0
Quote

Rapide et sale, et le stocker dans une variable:

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