web-dev-qa-db-fra.com

Comment utiliser su pour exécuter le reste du script bash en tant qu'utilisateur?

J'ai écrit un script qui prend comme argument une chaîne qui est une concaténation d'un nom d'utilisateur et d'un projet. Le script est supposé basculer (su) sur le nom d'utilisateur, cd sur un répertoire spécifique en fonction de la chaîne de projet.

Je veux fondamentalement faire:

su $USERNAME;  
cd /home/$USERNAME/$PROJECT;  
svn update;  

Le problème est qu'une fois que je fais un su ... il attend juste là. Cela a du sens puisque le flux d’exécution est passé à la commutation vers l’utilisateur. Une fois que je sors, le reste des choses s'exécutent mais cela ne fonctionne pas comme souhaité.

J'ai préfixé su à la commande svn mais la commande a échoué (c'est-à-dire qu'elle n'a pas mis à jour svn dans le répertoire souhaité).

Comment puis-je écrire un script qui permet à l'utilisateur de changer d'utilisateur et d'appeler svn (entre autres choses)?

113
Avery

L'astuce consiste à utiliser la commande "Sudo" au lieu de "su"

Vous devrez peut-être ajouter ceci

username1 ALL=(username2) NOPASSWD: /path/to/svn

dans votre fichier/etc/sudoers

et changez votre script pour:

Sudo -u username2 -H sh -c "cd /home/$USERNAME/$PROJECT; svn update" 

Où nomutilisateur2 correspond à l'utilisateur pour lequel vous souhaitez exécuter la commande SVN et nomutilisateur1 à l'utilisateur exécutant le script.

Si vous avez besoin de plusieurs utilisateurs pour exécuter ce script, utilisez un %groupname au lieu du nom d'utilisateur1

81
Kimvais

Beaucoup plus simple: utilisez Sudo pour exécuter un shell et utilisez un heredoc pour le nourrir.

#!/usr/bin/env bash
whoami
Sudo -i -u someuser bash << EOF
echo "In"
whoami
EOF
echo "Out"
whoami

(réponse à l'origine sur SuperUser )

87
Dan Dascalescu

Utilisez un script comme celui-ci pour exécuter le reste ou une partie du script sous un autre utilisateur:

#!/bin/sh

id

exec Sudo -u transmission /bin/sh - << eof

id

eof
53
Walder

Vous devez exécuter toutes les commandes d'utilisateur différent en tant que leur propre script. S'il ne s'agit que d'une ou de quelques commandes, alors inline devrait fonctionner. S'il y a beaucoup de commandes, il est probablement préférable de les déplacer dans leur propre fichier.

su -c "cd /home/$USERNAME/$PROJECT ; svn update" -m "$USERNAME" 
43
Douglas Leeder

Voici encore une autre approche, qui était plus pratique dans mon cas (je voulais simplement supprimer les privilèges root et faire le reste de mon script à partir d'un utilisateur restreint): vous pouvez faire en sorte que le script redémarre de l'utilisateur correct. Supposons qu'il soit initialement lancé en tant que root. Ensuite, cela ressemblera à ceci:

#!/bin/bash
if [ $UID -eq 0 ]; then
  user=$1
  dir=$2
  shift 2     # if you need some other parameters
  cd "$dir"
  exec su "$user" "$0" -- "$@"
  # nothing will be executed beyond that line,
  # because exec replaces running process with the new one
fi

echo "This will be run from user $UID"
...
35
MarSoft

Utilisez Sudo à la place

EDIT : Comme l'a souligné Douglas, vous ne pouvez pas utiliser cd dans Sudo car ce n'est pas un commande externe . Vous devez exécuter les commandes dans un sous-shell pour que le cd fonctionne.

Sudo -u $USERNAME -H sh -c "cd ~/$PROJECT; svn update"
Sudo -u $USERNAME -H cd ~/$PROJECT
Sudo -u $USERNAME svn update

Vous pouvez être invité à saisir le mot de passe de cet utilisateur, mais une seule fois.

7
iamamac

Il n'est pas possible de changer d'utilisateur dans un script Shell. Les solutions de contournement utilisant Sudo décrites dans d’autres réponses sont probablement votre meilleur choix.

Si vous êtes assez fou pour exécuter des scripts Perl en tant que root, vous pouvez le faire avec les variables $< $( $> $) qui contiennent les uid/gid réels/effectifs, par exemple:

#!/usr/bin/Perl -w
$user = shift;
if (!$<) {
    $> = getpwnam $user;
    $) = getgrnam $user;
} else {
    die 'must be root to change uid';
}
system('whoami');
6
P-Nuts

Cela a fonctionné pour moi

Je sépare mon "provisioning" de mon "démarrage".

 # Configure everything else ready to run 
  config.vm.provision :Shell, path: "provision.sh"
  config.vm.provision :Shell, path: "start_env.sh", run: "always"

puis dans mon start_env.sh

#!/usr/bin/env bash

echo "Starting Server Env"
#Java -jar /usr/lib/node_modules/Selenium-server-standalone-jar/jar/Selenium-server-standalone-2.40.0.jar  &
#(cd /vagrant_projects/myproj && Sudo -u vagrant -H sh -c "Nohup npm install 0<&- &>/dev/null &;bower install 0<&- &>/dev/null &")
cd /vagrant_projects/myproj
Nohup grunt connect:server:keepalive 0<&- &>/dev/null &
Nohup apimocker -c /vagrant_projects/myproj/mock_api_data/config.json 0<&- &>/dev/null &
2
httpete