63

I'm currently working on a bash script that installs and sets up various programs on a stock Linux system (currently, Ubuntu). Because it installs programs and copies a number of files to various folders that require elevated privileges, I've already done the standard "I need elevated privileges"-and-exit.

However, I would like, if possible, to be able to prompt the user for their sudo password and elevate the script's privileges automatically if the user doesn't run the script command with sudo (such as launching it from the GUI file manager), without the user having to restart the script.

As this is designed to run on stock Linux installs, any option that modifies the system won't work for my purposes. All options need to be contained to the script itself.

Is this possible within Bash? If so, what's the best (secure, yet concise) way to do this?

5
80

I run sudo directly from the script:

if [ $EUID != 0 ]; then
    sudo "$0" "$@"
    exit $?
fi
5
  • 3
    This will throw an error if EUID is not set for any reason – better quote it: [ "$EUID" != 0 ]
    – dessert
    Mar 3 '20 at 8:11
  • For those wondering: EUID (“effective user ID”) can be changed with setuid while UID can not.
    – dessert
    Mar 3 '20 at 8:19
  • It seems that something like sudo "$BASH_SOURCE" $(printf '%q ' "$@") is a safer alternative, according to this comment. Jun 17 '20 at 0:25
  • @SebastianSimon but it's bash-specific, while the script in the answer is POSIX-compliant
    – xeruf
    Mar 31 at 6:20
  • @SebastianSimon Do you know what "$0" "$@" actually gets wrong? The comment you linked claims it fails on whitespace and glob characters due to splicing an array into a string, but that is not true in my testing, and I thought the whole point of the special handling bash does with "$@" (rather than $@ or $*) is that it specifically handles properly expanding into a series of arguments with exactly the same contents, (regardless of whitespace within any of the arguments).
    – Ben
    Jun 28 at 23:05
22

Add this as the first line of the script:

[ "$UID" -eq 0 ] || exec sudo bash "$0" "$@"

Change sudo to gksu or gksudo if you prefer a graphical prompt.

3
  • Is there a way to do this on Debian, where there seems to be no sudo command? Jul 25 '15 at 18:23
  • @wrongusername install sudo, it's much better than using su. But if you really want, probably exec su -c "$0" "$@"
    – Kevin
    Jul 27 '15 at 17:23
  • This also won't inherit any environment variables from the current shell; use exec sudo -E bash "$0" "$@" to get that behavior.
    – gntskn
    Mar 14 at 18:06
17

I suggest:

#!/bin/bash

if (($EUID != 0)); then
  if [[ -t 1 ]]; then
    sudo "$0" "$@"
  else
    exec 1>output_file
    gksu "$0 $@"
  fi
  exit
fi

# some example stuff
ls -l /root
echo "app: $0"
for f; do
  echo ">$f<"
done
3
  • What does if [[ -t 1 ]]; check for?
    – Shauna
    Jan 10 '12 at 20:05
  • Ah, ok. I figured it had something to do with terminal vs GUI, but wasn't sure what the if statement itself was checking.
    – Shauna
    Jan 10 '12 at 20:24
  • Amazing, thanks! Mar 15 '19 at 18:46
4

An example script that I don't mind sharing::

#!/bin/bash
[ "$UID" -eq 0 ] || exec sudo "$0" "$@" && echo -n "sudo bash what: "
read WHAT
sudo $WHAT
2
  • [ "$UID" -eq 0 ] || exec sudo "$0" "$@" -- Looks like a really efficient one liner! Nice! Dec 17 '18 at 18:41
  • Would it make sense to use Effective UID here, $EUDI, or always the same outcome? E.g., [[ "$EUID" -eq 0 ]] || exec sudo "$0" "$@" Dec 17 '18 at 19:04
0

I use visudo to edit the sudoers file as follows:

  • In the line with your user, add this next to the username:
    ALL=(ALL)       NOPASSWD: ALL
    
    then save.
  • When that user
    sudo su -
    
    he will be logged on as root without entering a password.
0

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.