A sample script can be as below:

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?

  • 15
    sudo su makes my eyes hurt. – gelraen Apr 2 '13 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 '13 at 16:16
  • 1
    Can't you just use sudo -s, though? – Joe Z. Apr 2 '13 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 '13 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 '13 at 9:27

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

ls /root

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

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

[ `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 ||

| improve this answer | |
  • 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 '13 at 15:49
  • Agreed, and I will update the answer to explain this. – Johan Apr 2 '13 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 '13 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 '13 at 16:35
  • @JoelDavis I always run into the wall of "what if there are spaces characters in the arguments". I've never found a satisfactory solution. Once I wrote a script which put out its arguments into a temp file, one argument per line, and then called whatever it needed and passed to that final script the argument of what file to read to find the original arguments in. – Johan Apr 3 '13 at 9:20

Use the following in script.

sudo su <<HERE
ls /root

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

| improve this answer | |
  • 7
    sudo su is calling two programs. Use sudo -s <<HEREDOC or su user <<HEREDOC ... Stupid 5 minute limit. – Johan Apr 2 '13 at 16:13

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.

| improve this answer | |
  • 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. – Hongxu Chen Apr 2 '13 at 13:27

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).


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.

| improve this answer | |
  • 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 '13 at 22:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.