Execute nvm (função bash) via sudo

4

Eu quero escrever um script de inicialização que deve basicamente ser executado

nvm use v0.11.12 && forever start /srv/index.js

como o usuário webconfig . nvm é uma função do shell declarada em ~webconfig/.nvm/nvm.sh , incluída por source ~/.nvm/nvm.sh em webconfig ' .bashrc .

Eu tentei o seguinte:

sudo -H -i -u webconfig nvm

echo "nvm" | sudo -H -i -u webconfig

mas eles falham com

-bash: nvm: command not found
-bash: line 1: nvm: command not found

Quando executo sudo -H -i -u webconfig e digito nvm manualmente nesse shell, ele funciona. O que estou fazendo errado?

    
por Yogu 21.04.2014 / 12:44

3 respostas

6

O problema aqui, como é frequentemente o caso, é sobre os diferentes tipos de shell:

  • Quando você abre um emulador de terminal ( gnome-terminal , por exemplo), está executando o que é conhecido como um shell interativo, sem login .

  • Quando você faz login na sua máquina a partir da linha de comando ou executa um comando como su username ou sudo -u username , você está executando um shell login interativo .

Então, dependendo do tipo de shell que você iniciou, um conjunto diferente de arquivos de inicialização é lido. De man bash :

   When  bash is invoked as an interactive login shell, or as a non-inter‐
   active shell with the --login option, it first reads and executes  com‐
   mands  from  the file /etc/profile, if that file exists.  After reading
   that file, it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile,
   in  that order, and reads and executes commands from the first one that
   exists and is readable.  The --noprofile option may be  used  when  the
   shell is started to inhibit this behavior.

Em outras palavras, ~/.bashrc é ignorado pelos shell de login. Como você está usando a opção -i para sudo , os arquivos de inicialização para o shell de login do usuário estão sendo lidos (de man sudo ):

 -i, --login
             Run the shell specified by the target user's password data‐
             base entry as a login shell.  This means that login-specific
             resource files such as .profile or .login will be read by the
             shell. 

Então, o que você pode fazer é

  1. Defina a função em ~/.profile ou ~/.bash_profile do usuário. Tenha em mente que ~/.profile será ignorado se ~/.bash_profile existir. Também tenha em mente que ~/.bash_profile é específico do bash, então eu usaria .profile , apenas certifique-se de que ~/.bash_profile não exista.

  2. Origem ~/.nvm/nvm.sh de ~/.profile .

por 21.04.2014 / 13:16
4

@terdon já adicionou alguns bons detalhes sobre isso, então não vou repetir isso aqui. Para reafirmar, a causa do problema provavelmente está no comportamento um tanto estranho que bash tem quando chamado como um shell de login, pois ele não origina automaticamente o .bashrc e, em vez disso, procura ~/.bash_profile , ~/.bash_login ou ~/.profile apenas.

É prática comum adicionar código a um desses arquivos de perfil para originar o .bashrc . Por padrão, eu tenho o seguinte código em ~/.profile :

if [ "$BASH" ]; then
  if [ -f ~/.bashrc ]; then
    . ~/.bashrc
  fi
fi

Atualizar

Dos comentários abaixo, acho que a melhor solução é provavelmente remover a linha [ -z "$PS1" ] && return do .bashrc e deixar todo o resto como está.

    
por 21.04.2014 / 13:35
1
sudo -Hu webconfig bash -c '. ~/.nvm/nvm.sh && nvm'
    
por 21.04.2014 / 14:54