How do I use su to execute the rest of the bash script as that user?

265,791

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
Share:
265,791

Related videos on Youtube

Son of the Wai-Pan
Author by

Son of the Wai-Pan

Updated on February 11, 2022

Comments

  • Son of the Wai-Pan
    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
    Douglas Leeder over 14 years
    That won't work though - the cd will be lost after the first sudo has finished executing.
  • iamamac
    iamamac over 14 years
    Actually, you can't even call cd directly because it is not an external command.
  • Kimvais
    Kimvais over 14 years
    -1 as It IS possible with sudo to temporarily gain other user's rights.
  • P-Nuts
    P-Nuts over 14 years
    It'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
    Kim Stacks about 11 years
    I 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
    Hippyjim over 10 years
    I did this - but it still asked me for a password.
  • Kimvais
    Kimvais over 10 years
    @Hippyjim are you sure you got the usernames right way round?
  • Hippyjim
    Hippyjim over 10 years
    I did - it turns out that I also needed to allow usage of /bin/bash as well.
  • Bryan Larsen
    Bryan Larsen over 9 years
    You may want to use "sudo -i -u ..." to ensure that stuff like $HOME is set correctly.
  • tripleee
    tripleee about 9 years
    Whether you use sudo or su is of secondary importance, though sudo is a lot more secure and convenient.
  • helvete
    helvete over 8 years
    This is the only correct answer. The sudo is not necessary for this.
  • SirVer
    SirVer almost 8 years
    I wonder why this is not higher rated. It is solving the original question the best while keeping everything in bash.
  • Nitin Jadhav
    Nitin Jadhav over 7 years
    Sorry for noob question, but whats an id here?
  • Mohammed Noureldin
    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 of id which will return the name instead of the id
  • Nitin Jadhav
    Nitin Jadhav over 7 years
    @MohammedNoureldin Thanks!
  • mixel
    mixel over 7 years
    You may need also to provide shell with su -s /bin/bash.
  • not2savvy
    not2savvy almost 7 years
    This answer worked best. I recommend to use option -i to get someuser's expected environment.
  • rfinz
    rfinz almost 7 years
    best solution for root users
  • Tricky
    Tricky about 6 years
    Best answer for those who don't have sudo installed by default (I'm looking at you AIX)
  • Tricky
    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
    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
    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
    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
    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
    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 even sudo -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
    Charles Duffy almost 6 years
    The 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 might printf -v arg_q '%q ' "$0" "$@" and then use su "$USERNAME" -c "/usr/bin/bash -l $arg_q"
  • Trendfischer
    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
    cghislai almost 6 years
    Or runuser -u $user -- "$@", as stated in su(1)
  • MarSoft
    MarSoft almost 6 years
    Yes, runuser can be used in an opposite situation - i.e. to drop root privileged.
  • 3bdalla
    3bdalla over 5 years
    Epic solution !
  • dotslashlu
    dotslashlu over 5 years
    How to make variables available in herdoc's scope?
  • macieksk
    macieksk over 5 years
    exec su "$user" "$0" -- "$@"
  • MarSoft
    MarSoft over 5 years
    Thanks @macieksk, nice catch. Will update. The -- is really useful.
  • AhmedRana
    AhmedRana almost 5 years
    on AIX it throws this error ksh: sh: 0403-006 Execute permission denied.
  • MarSoft
    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 to bash, and current environment variables are expanded in it. So if you set MYVAR=42 and then use heredoc ... bash <<EOF ↓ echo $MYVAR ↓ EOF (↓ denoting line break) then you will see 42 printed.
  • Znik
    Znik about 4 years
    Presented 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
    MarSoft about 4 years
    @Znik, if we test $HOME then it may break if root's home directory was set to something other than /root in /etc/passwd. This is sometimes the case in some embedded systems.
  • darkdragon
    darkdragon almost 4 years
    This seems to use the users default shell instead of the one specified in the shebang. Anyone has an idea how to change this?
  • darkdragon
    darkdragon almost 4 years
    Replacing the exec line with exec sudo -i -u "$user" $( readlink -f "$0" ) -- "$@" works for me.
  • DJ_Stuffy_K
    DJ_Stuffy_K about 3 years
    Hi @dan-dascalescu what if the user we are changing to has a password that needs to be entered?
  • Dan Dascalescu
    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.