在我的服务器上,我有一个由 sudo 用户运行的脚本。它包含以下几行:
sudo -u nonsudoer -H bash -l << HERE
echo -n "Execute code as user "; whoami
cd bundle/programs/server
echo -n "Install package at "; pwd
npm install --production
HERE
这些行产生以下输出:
Execute code as user nonsudoer
Install package at /var/www/example/bundle/programs/server
bash: line 4: npm: command not found
但是,当我手动运行这些行时......
$ sudo -u nonsudoer -H bash -l
manpath: can't set the locale; make sure $LC_* and $LANG are correct
$ echo -n "Execute code as user "; whoami
Execute code as user nonsudoer
$ cd bundle/programs/server
$ echo -n "Install package at "; pwd
Install package at /var/www/example/bundle/programs/server
$ npm install --production
<command successful; output clipped>
$ exit
... 一切按预期进行。我的脚本中哪里做错了?
答案1
当你调用bash -l
shell 并在命令行上与其交互时,新的 bash 登录 shell 是交互的,您可以通过检查特殊参数的值来确认$-
:
steeldriver@machine:~$ sudo -u testuser -H bash -l
testuser@machine:/home/steeldriver$ echo $-
himBHs
testuser@machine:/home/steeldriver$ exit
logout
当你bash -l
通过此处文档调用时,你会得到一个非交互式登录外壳:
steeldriver@machine:~$ sudo -u testuser -H bash -l << HERE
echo \$-
HERE
hBs
steeldriver@machine:~$
(请注意,我进行了转义,$-
以防止它被交互式父shell扩展)。
根据man bash
,bash 登录 shell 使用 进行初始化~/.profile
(~/.bash_profile
如果存在),而非登录 shell 使用 进行初始化。Ubuntu 通过有条件地从 进行~/.bashrc
获取,让情况变得有些混乱。但是 rc 文件内置了交互性检查:~/.bashrc
~/.profile
$ sudo -u testuser -H head /home/testuser/.bashrc
# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
因此,在非交互式情况下,~/.bashrc
几乎立即终止,绕过PATH
您稍后在文件中添加的任何规范,而在交互式情况下,您的全部内容~/.bashrc
都会被处理(尽管处于登录 shell 中),并且您的 npmPATH
可能会被添加到那里。