如何使用 su 作为该用户执行 bash 脚本的其余部分?

我编写了一个脚本,它使用一个字符串作为参数,该字符串是用户名和项目的串联。脚本应该切换(su)到用户名,cd 根据项目字符串切换到特定的目录。

我基本上想做的是:

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

问题是,一旦我做了一个... 它只是等待在那里。这是有意义的,因为执行流已经传递到切换到用户。一旦我退出,其余的事情就会执行,但是它并不像我想要的那样工作。

我将 su 添加到 svn 命令之前,但是命令失败了(也就是说,它没有在所需的目录中更新 svn)。

如何编写一个允许用户切换用户和调用 svn (以及其他事情)的脚本?

282192 次浏览

诀窍是使用“ sudo”命令而不是“ su”命令

你可能需要加上这个

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

到您的/etc/sudoers 文件

然后把你的剧本改成:

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

其中 username2是您希望运行 SVN 命令的用户,username1是运行脚本的用户。

如果需要多个用户来运行此脚本,请使用 %groupname而不是 username1

使用 sudo代替

编辑 : 正如 Douglas 指出的,在 sudo中不能使用 cd,因为它不是 外部命令。您必须在 subshell 中运行命令才能使 cd工作。

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

sudo -u $USERNAME -H cd ~/$PROJECT
sudo -u $USERNAME svn update

您可能会被要求输入该用户的密码,但只能输入一次。

您需要将所有不同用户的命令作为它们自己的脚本执行。如果只有一个或几个命令,那么内联应该可以工作。如果有很多命令,那么最好将它们移动到自己的文件中。

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

在 shell 脚本中不可能更改用户。使用其他答案中描述的 sudo 的工作区可能是最佳选择。

如果你疯狂到以 root 用户身份运行 perl 脚本,你可以使用 $< $( $> $)变量来实现,这些变量包含了真实/有效的 uid/gid,例如:

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

使用下面这样的脚本在另一个用户下执行脚本的其余部分:

#!/bin/sh


id


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


id


eof

简单得多: 使用 sudo运行 shell 并使用 Herdoc为其提供命令。

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

(答案 最初出现在《超级用户》上)

这招对我很管用

我把“供给”从“创业”中分离出来。

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

然后在我的 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 &

这里还有另一种方法,在我的例子中更方便(我只是想删除 root 特权,并从受限用户处完成脚本的其余部分) : 您可以让脚本从正确的用户处重新启动。这种方法比使用带有“嵌套脚本”的 sudosu -c更具可读性。让我们假设它最初是以 root 用户身份启动的。然后代码会是这样的:

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

受@MarSoft想法的启发,我把台词改成了这样:

USERNAME='desireduser'
COMMAND=$0
COMMANDARGS="$(printf " %q" "${@}")"
if [ $(whoami) != "$USERNAME" ]; then
exec sudo -E su $USERNAME -c "/usr/bin/bash -l $COMMAND $COMMANDARGS"
exit
fi

我已经使用 sudo来允许脚本的少密码执行。如果要为用户输入密码,请删除 sudo。如果不需要环境变量,请从 sudo 中删除 -E

/usr/bin/bash -l确保对初始化的环境执行 profile.d脚本。