I am writing a script (actually a combination of scripts and makefile) that installs external dependencies: some apt-get commands, some git cloning, building, installing, adding users to groups, ...

Some of the operations in these scripts require superuser permissions, some don't.

Until now I have run the entire make process with sudo, but it has some drawbacks:

  • git repos I clone get root as owner, which means I can't modify them afterwards without sudo or chown
  • the scripts that add users to groups don't know which user to add since whoami returns root

What is the best way of running as superuser only the commands that require it? Ideally the process would still require me to enter my sudo password, but only once at the very beginning of the install process. It would then forget it at the very end, but keep it all the time until then (it can take several hours).

The solutions I have found online include:

  • sudo -v at the begninning of the script, but if I understand correctly this times out. My script could be running for a couple of hours
  • running the script with sudo, but the commands that do not need superuser with sudo -u $(logname) <command>. This is what I do now, but it feels like it should be the other way around.

Ideally, I would like my script to:

  1. ask for superuser credentials
  2. run normal commands as the logged in user
  3. run sudo commands with the credentials entered at step 1
  4. sudo -k to close the superuser session
  • 2
    You can still run everything as sudo, and your script can check the SUDO_USER environment variable. If present, it will contain the username of the user invoking sudo. So you can (as root) chown $SUDO_USER:$SUDO_GID $your_files. Similarly, you can check these variables so your adduser commands know which user to add. – roadmr Feb 13 '15 at 16:26
  • ...or run everything as root and use su $SUDO_USER -c command for the commands run as normal user. – Rmano Feb 17 '15 at 22:26

Since you have sudo access, create a sudoers file for yourself, then delete it when the script is done:

# grant this user access to the sudo commands without passwords
# add all required cmds to the CMDS alias
sudo tee /etc/sudoers.d/$USER <<END
$USER $(hostname) = NOPASSWD: /usr/bin/apt-get, /usr/sbin/adduser, /bin/rm, ...

# your script goes here
sudo apt-get install ...
git clone ...
sudo adduser group2 $USER
sudo adduser group1 $USER
: ...

# then, remove the sudo access
sudo /bin/rm /etc/sudoers.d/$USER
sudo -k

One way, that I wouldn't generally recommend, is to read in the password yourself, and use sudo's -S option to pass the password as and when needed:

#! /bin/bash
IFS= read -rsp 'Enter your password: ' password
git clone ...
sudo -S apt-get install foo -y <<<"$password"

From man sudo:

 -S, --stdin
             Write the prompt to the standard error and read the password
             from the standard input instead of using the terminal device.
             The password must be followed by a newline character.
  • 1
    Is that safe? echo "$password"?? – αғsнιη Feb 13 '15 at 16:50
  • @KasiyA echo "$password" wouldn't be, but heredocs and herestrings are slightly more safe. They're not visible on the command line shown by the usual tools. – muru Feb 13 '15 at 16:52
  • 1
    I think, strictly speaking, echo "$password" on the left side of a pipe is safe in a bash script. echo is a shell builtin; /bin/echo doesn't run when it's called as simply echo .... Some other shells have an echo builtin (dash, for example), but Bourne-style shells aren't required to have one. So I think echo "$password" | is acceptable in bash but may be best avoided in case someone ports the script to another shell without noticing the issue. I use a non-portable [[ instead of [ in that script to avert the same sort of problem. @KasiyA – Eliah Kagan May 11 '15 at 19:36

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.