How do I use su to execute the rest of the bash script as that user?
Solution 1
The trick is to use "sudo" command instead of "su"
You may need to add this
username1 ALL=(username2) NOPASSWD: /path/to/svn
to your /etc/sudoers file
and change your script to:
sudo -u username2 -H sh -c "cd /home/$USERNAME/$PROJECT; svn update"
Where username2 is the user you want to run the SVN command as and username1 is the user running the script.
If you need multiple users to run this script, use a %groupname
instead of the username1
Solution 2
Much simpler: use sudo
to run a shell and use a heredoc to feed it commands.
#!/usr/bin/env bash
whoami
sudo -i -u someuser bash << EOF
echo "In"
whoami
EOF
echo "Out"
whoami
(answer originally on SuperUser)
Solution 3
You need to execute all the different-user commands as their own script. If it's just one, or a few commands, then inline should work. If it's lots of commands then it's probably best to move them to their own file.
su -c "cd /home/$USERNAME/$PROJECT ; svn update" -m "$USERNAME"
Solution 4
Here is yet another approach, which was more convenient in my case (I just wanted to drop root privileges and do the rest of my script from restricted user): you can make the script restart itself from the correct user. This approach is more readable than using sudo
or su -c
with a "nested script". Let's suppose it is started as root initially. Then the code will look like this:
#!/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"
...
Solution 5
Use a script like the following to execute the rest or part of the script under another user:
#!/bin/sh
id
exec sudo -u transmission /bin/sh - << eof
id
eof
Related videos on Youtube
Son of the Wai-Pan
Updated on February 11, 2022Comments
-
Son of the Wai-Pan about 2 years
I've written a script that takes, as an argument, a string that is a concatenation of a username and a project. The script is supposed to switch (su) to the username, cd to a specific directory based upon the project string.
I basically want to do:
su $USERNAME; cd /home/$USERNAME/$PROJECT; svn update;
The problem is that once I do an su... it just waits there. Which makes sense since the flow of execution has passed to switching to the user. Once I exit, then the rest of the things execute but it doesn't work as desired.
I prepended su to the svn command but the command failed (i.e. it didn't update svn in the directory desired).
How do I write a script that allows the user to switch user and invoke svn (among other things)?
-
Douglas Leeder over 14 yearsThat won't work though - the cd will be lost after the first sudo has finished executing.
-
iamamac over 14 yearsActually, you can't even call cd directly because it is not an external command.
-
Kimvais over 14 years-1 as It IS possible with sudo to temporarily gain other user's rights.
-
P-Nuts over 14 yearsIt's not possible in the sense that the user the shell script itself runs as can't be changed (which is what the original question asked). Invoking other processes with sudo doesn't change who the script itself is running as.
-
Kim Stacks about 11 yearsI have a similar issue, but I wanted to run
chsh
for the other users. My issue is listed here at stackoverflow.com/q/15307289/80353 How do I adapt your answer in my situation? -
Hippyjim over 10 yearsI did this - but it still asked me for a password.
-
Kimvais over 10 years@Hippyjim are you sure you got the usernames right way round?
-
Hippyjim over 10 yearsI did - it turns out that I also needed to allow usage of /bin/bash as well.
-
Bryan Larsen over 9 yearsYou may want to use "sudo -i -u ..." to ensure that stuff like $HOME is set correctly.
-
tripleee about 9 yearsWhether you use
sudo
orsu
is of secondary importance, thoughsudo
is a lot more secure and convenient. -
helvete over 8 yearsThis is the only correct answer. The sudo is not necessary for this.
-
SirVer almost 8 yearsI wonder why this is not higher rated. It is solving the original question the best while keeping everything in bash.
-
Nitin Jadhav over 7 yearsSorry for noob question, but whats an id here?
-
Mohammed Noureldin over 7 years@NitinJadhav, he used it here just to show the ID of the current user, the ID of root is 0, so the first id will show you some number, but the second one will definetly show 0 (because the second one was executed inside a block run by root). You can user
whoami
instead ofid
which will return the name instead of the id -
Nitin Jadhav over 7 years@MohammedNoureldin Thanks!
-
mixel over 7 yearsYou may need also to provide shell with
su -s /bin/bash
. -
not2savvy almost 7 yearsThis answer worked best. I recommend to use option
-i
to getsomeuser
's expected environment. -
rfinz almost 7 yearsbest solution for root users
-
Tricky about 6 yearsBest answer for those who don't have sudo installed by default (I'm looking at you AIX)
-
Tricky about 6 years
sudo
may be convenient but it's no good if its not out of the box (like on AIX).su -c 'commands'
is the correct answer. -
Tricky about 6 years
sudo
may be convenient but it's no good if its not out of the box (like on AIX).su -c 'commands'
is the correct answer. -
Tricky about 6 years
sudo
may be convenient but it's no good if its not out of the box (like on AIX).su -c 'commands'
is the correct answer. -
Tricky about 6 years
sudo
may be convenient but it's no good if its not out of the box (like on AIX).su -c 'commands'
is the correct answer. -
Tricky about 6 years
sudo
may be convenient but it's no good if its not out of the box (like on AIX).su -c 'commands'
is the correct answer. -
Trendfischer about 6 years@Tricky Perhaps read the full answer, it already suggests removing
sudo
. In fact, sudo is not that simple, in a lot of cases you need evensudo -E
and a configuration entry in sudoers.d to allow execution without tty with!requiretty
. But there are a lot of cases, where sudo is necessary for automatic called scripts, where a password dialog might interfere. Thus I would not remove it from a standard solution. -
Charles Duffy almost 6 yearsThe code in question is outright buggy -- it'll break script names or arguments with spaces; keep in mind that putting
"$@"
inside of a string means that arguments past the first one are appended into a separate string, not included in the-c
argument. If you wanted to make it safe, you mightprintf -v arg_q '%q ' "$0" "$@"
and then usesu "$USERNAME" -c "/usr/bin/bash -l $arg_q"
-
Trendfischer almost 6 years@CharlesDuffy You are right! I simplified my production script too much for this answer :-( Just adding a
COMMANDARGS=$@
solves the problem with-c
. Arguments with spaces were not a problem before, but I implemented your good input. I just had to do some experiments to make it work. I've edited the question and hopefully I did not paste another bug. Thanks for your comment, humiliating but necessary. -
cghislai almost 6 yearsOr
runuser -u $user -- "$@"
, as stated in su(1) -
MarSoft almost 6 yearsYes,
runuser
can be used in an opposite situation - i.e. to drop root privileged. -
3bdalla over 5 yearsEpic solution !
-
dotslashlu over 5 yearsHow to make variables available in herdoc's scope?
-
macieksk over 5 years
exec su "$user" "$0" -- "$@"
-
MarSoft over 5 yearsThanks @macieksk, nice catch. Will update. The
--
is really useful. -
AhmedRana almost 5 yearson AIX it throws this error ksh: sh: 0403-006 Execute permission denied.
-
MarSoft over 4 years@dotslashlu, it is not possible directly since heredoc contents will be executed within a subshell, and
sudo
drops all environment variables by default. But in fact heredoc is a plain string passed tobash
, and current environment variables are expanded in it. So if you setMYVAR=42
and then use heredoc... bash <<EOF ↓ echo $MYVAR ↓ EOF
(↓ denoting line break) then you will see42
printed. -
Znik about 4 yearsPresented approach is the best of the all and is complete. All is written inside single script, and all uses bash. Effectively, this script is runned twice. At first script test it is root, then prepare environment, and change user by su. But do it with exec command, then there is only single script instance. With second loop, phrase if/fi is ommited, then script directly do prepared action. In this example it is echo. All of other approaches resolve problem only partially. Of course this script can be run under sh not bash, but we must test $HOME special variable, not $UID
-
MarSoft about 4 years@Znik, if we test
$HOME
then it may break ifroot
's home directory was set to something other than/root
in/etc/passwd
. This is sometimes the case in some embedded systems. -
darkdragon almost 4 yearsThis seems to use the users default shell instead of the one specified in the shebang. Anyone has an idea how to change this?
-
darkdragon almost 4 yearsReplacing the exec line with
exec sudo -i -u "$user" $( readlink -f "$0" ) -- "$@"
works for me. -
DJ_Stuffy_K about 3 yearsHi @dan-dascalescu what if the user we are changing to has a password that needs to be entered?
-
Dan Dascalescu about 3 years@DJ_Stuffy_K: it doesn't matter. You only need to enter the password of the currently logged in user, which needs root privileges. See differences between sudo and su.