46

A sample script can be as below:

#!/bin/bash
sudo su
ls /root

When using ./test.sh as the normal user, instead run ls as super user and exit, it switches to root; and when I logout, it executes ls /root as the normal user.

Can anybody tell me about the mechanism about it?

13
  • 18
    sudo su makes my eyes hurt.
    – gelraen
    Apr 2, 2013 at 12:44
  • It is used because people don't know sudo well enough, and so they need a way to run su on systems where root is secured by a deliberately corrupted password. But yes sudo "redundifies" the use of su.
    – Johan
    Apr 2, 2013 at 16:16
  • 1
    Can't you just use sudo -s, though?
    – Joe Z.
    Apr 2, 2013 at 17:04
  • @Johan, I often use sudo su because I am more used to the options of su than I am of those of sudo. I know the options of sudo well enough, but I can type the su ones faster. But yes I guess that means I don't know sudo well enough.
    – user606723
    Apr 2, 2013 at 18:51
  • 1
    I just checked the sudo man page. It appears sudo -i is akin to su - while sudo -s operates like su (without the dash)
    – Johan
    Apr 3, 2013 at 9:27

6 Answers 6

57

The commands in a script execute one by one, independently. The Script itself as the parent of all commands in the script, is another independent process and the su command does not and can not change it to root: the su command creates a new process with root privileges.

After that su command completes, the parent process, still running as the same user, will execute the rest of the script.

What you want to do is write a wrapper script. The privileged commands goes into the main script, for example ~/main.sh

#!/bin/sh
ls /root

The wrapper script calls the main script with root permissions, like this

#!/bin/sh
su -c ~/main.sh root

To launch this process you run the wrapper, which in turn launches the main script after switching user to the root user.

This wrapper technique can be used to turn the script into a wrapper around itself. Basically check to see if it is running as root, if not, use "su" to re-launch itself.

$0 is a handy way of making a script refer to itself, and the whoami command can tell us who we are (are we root?)

So the main script with built-in wrapper becomes

#!/bin/sh
[ `whoami` = root ] || exec su -c $0 root
ls /root

Note the use of exec. It means "replace this program by", which effectively ends its execution and starts the new program, launched by su, with root, to run from the top. The replacement instance is "root" so it doesn't execute the right side of the ||

9
  • 1
    fwiw, an addendum to this point. If I were writing a script like it I would just do an if statement at the beginning that checks $EUID and if it's not zero sudo itself and exit, otherwise continue with the script execution.
    – Bratchley
    Apr 2, 2013 at 15:49
  • Agreed, and I will update the answer to explain this.
    – Johan
    Apr 2, 2013 at 15:54
  • 2
    Perhaps its a bit archaic but i love absolute paths to every executeable so someone cant change the ~/main.sh script into something nefarious. Attacking the USER part of the script
    – artifex
    Apr 2, 2013 at 16:16
  • 2
    You may also want to catch the arguments that were passed to it by including a reference to $*
    – Bratchley
    Apr 2, 2013 at 16:35
  • 1
    In setups where the default user has to use sudo (e.g. Ubuntu, AWS AMIs), the solution can be amended to read: [ `whoami` = root ] || exec sudo su -c $0 root Feb 13, 2018 at 12:53
24

Use the following in script.

sudo su <<HERE
ls /root
HERE

The code between the HERE block will be run as root.

2
  • 8
    sudo su is calling two programs. Use sudo -s <<HEREDOC or su user <<HEREDOC ... Stupid 5 minute limit.
    – Johan
    Apr 2, 2013 at 16:13
  • Remember the commands in heredoc cannot indent, even with <<-. And args passed to the main process can pass to subshell of sudo su if HERE is without quotes.
    – WesternGun
    Jul 6, 2022 at 12:28
6

Without further arguments su will run the login shell for root. That's what the first line of your script actually does. When you exit, the login shell closes, su returns and your script continues execution, that is with the second line: ls /root. I think you can simply sudo ls /root to do what you want.

1
  • Yeah, I know I can do this for ls, but this is just a sample. In fact I need to do a lot more things with root privilege:-) So I prefer @Ankit's answer. Apr 2, 2013 at 13:27
1

Once you fire sudo su a new process with the effective userid (euid=EUID) of super user forked, hence we have new bash running at different process id (pid=PID) associated with the same terminal (tname=TTY).

Explanation

Suppose after firing ps -A | grep bash you have 21460 pts/2 00:00:00 bash as output. Now, when you execute ./test.sh both commands sudo su and ls /root will get spooled to PID 21460. After execution when you have root as active user hit ps -A | grep bash again, you will notice a new bash running on PID say, 21570. Exiting from root bash will kill newly forked bash reverting to user's bash and hence executes the spooled command ls /root before releasing the prompt.

1
  • If using su or sudo was "persistent" in bash (or anywhere else) it would create many more problems than it solved. You need to do the minimum possible as root for safety and security. The main point of having su and sudo (other than security!) is to make you think carefully about what needs root privileges.
    – Joe
    Apr 5, 2013 at 22:57
0

If you need a script to run with root privileges, put this in the beginning of it:

if [ ! $(whoami)=”root” ]; then
    exec sudo ”$0” ”$@”
    echo ”Error: failed to execute sudo” >&2
    exit 1
fi

This will re-execute the script with the same parameters, but prefixed with sudo. If the sudo command succesfully starts, it replaces the first script process (because of exec) and only the sudoed version will go forward. If the line after exec sudo gets executed, it means the shell failed to even start sudo and something is really wrong.

If the user is authorized to run the script, sudo may or may not request a password; if a wrong password is entered or the user is not authorized to run the script as root, a standard sudo error message will be displayed.

If succesful, sudo will start the script a second time, now running with root privileges. The if expression will now skip the exec sudo... step and continue into the rest of the script.

So the processes will be:

  • parent: the command line session where the user runs the script
  • child: initially the shell running the script as the user, but turns into sudo because of exec
  • grandchild: a shell running the script as root.
-2

so here is your typical used case 1.in your bash there are lines which executes without sudo 2.also in your bash there are lines which needs a super user 3.after the execution of lines which required superused preivelage you want the control back into your script and then go on with usual business

well if thats what you need here is a sample #!/bin/bash if [[ $(cat /proc/net/dev |grep br0) ]]; then echo "Creating bridge" pwd cd ../../ cd /proc/sys/net pwd modprobe br_netfilter cd bridge sudo -s for f in bridge-nf-*; do echo 0 > $f;done brctl show echo "type exit to continue" cd ../../../../ cd /home/shino/Desktop/openwrt_virt pwd

fi

just check the line sudo -s thats all you need save this into a bash and try thank me later

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .