Why can't I use 'sudo su' in a shell script? How to make a shell script run with sudo automatically

I cannot understand what is wrong with this. When I run it in the terminal and enter the password, nothing happens, but if I run each command separately in the terminal, it works. Thanks!

#!/bin/bash sudo su; mkdir /opt/D3GO/; cp `pwd`/D3GO /opt/D3GO/; cp `pwd`/D3GO.png /opt/D3GO/; cp `pwd`/D3GO.desktop /usr/share/applications/; chmod +x /opt/D3GO/D3GO 
+6
source share
6 answers

The sudo su launches the interactive root shell, but will not convert the current shell to the root shell.

The idiom to do what you want is something like this (thanks @CharlesDuffy for extra thoroughness):

 #check for root UID=$(id -u) if [ x$UID != x0 ] then #Beware of how you compose the command printf -v cmd_str '%q ' "$0" " $@ " exec sudo su -c "$cmd_str" fi #I am root mkdir /opt/D3GO/ #and the rest of your commands 

The idea is to check if the current user is root, and if not, repeat the same command with su

+14
source

sudo su is not starting a command inside a shell - it is starting a new shell.

This new shell no longer runs your script, and the old shell that runs the script waits until the new one is completed before it continues.

+8
source

You can use Here Documents to redirect input to the interactive shell script. The << operator is an instruction to read input until it finds a line containing the specified delimiter, like EOF (end of file).

 sudo su <<EOF echo "code" EOF 

eg.

 #!/bin/bash sudo su <<EOF mkdir /opt/D3GO/ cp `pwd`/D3GO /opt/D3GO/ cp `pwd`/D3GO.png /opt/D3GO/ cp `pwd`/D3GO.desktop /usr/share/applications/ chmod +x /opt/D3GO/D3GO EOF 
+7
source

the accepted answer works well, but the idiom for the script callback with sudo on request can be simplified and made more portable :

 [[ $(id -u) -eq 0 ]] || exec sudo /bin/bash -c "$(printf '%q ' "$BASH_SOURCE" " $@ ")" 
  • Using [[ ... ]] instead of [ ... ] makes it impossible to add x to operands (or double quoting LHS).

  • Using bash -c instead of su -c to interpret the restored command line makes the command more portable since not all platforms support su -c (for example, macOS does not work).

  • In bash , $BASH_SOURCE is usually a more reliable way to reference an executable script.


Using the aforementioned approach, any references to variables or command / arithmetic substitutions in arguments are invariably expanded by the calling shell.

If you want a deferred extension so that variable references do not expand until the sudo shell is started, in the context of the root user, use this:

 (( __reinvoked )) || exec sudo -s __reinvoked=1 "$BASH_SOURCE" " $@ " 

Note that you will need to quote any arguments that contain references to variables or replace commands so that they are deferred; for example, '$USER' .

Note the use of the ad-hoc __reinvoked environment variable to ensure that the call is __reinvoked exactly once (even if it has already been run as the root user).


Here's a sample script that demonstrates the first method:

  • If not invoked as root, the script re-runs itself with sudo -s , passing all arguments through as-is.

  • If it has not been authenticated before and is still in the waiting period, sudo offer an administrator password.

 #!/bin/bash [[ $(id -u) -eq 0 ]] || exec sudo /bin/bash -c "$(printf '%q ' "$BASH_SOURCE" " $@ ")" # Print the username and all arguments. echo "Running as: $(id -un)" echo "Arguments:" for arg; do echo " $((++i)): [$arg]"; done 

acfreitas' helpful answer demonstrates the script -inide-a-script technique where document is used to provide shell code via stdin to sudo su .
Again, sudo -s sufficient and important to quote :

 sudo -s -H <<'EOF' echo "$HOME" EOF 

Note how the document-separator, EOF , is disclosed in this case to prevent the contents of the document from being pre-interpreted by the current shell.
If you did not specify (any part) of EOF , $HOME will expand to the user's current home directory.

If you want to mix forward and the extension delay , leave the opening here - the document delimiter without quotes and selectively \ -quote $ instances:

 sudo -s -H <<EOF echo "Called by: $USER; root home dir: \$HOME" EOF 
+4
source

Since running "sudo su" opens a new shell, and the command does not return until you exit this shell. Perhaps split the script into 2 files: sudo is started first and the 2nd script is run under sudo.

+2
source

sudo su will try to start a new shell with root privileges. When this new shell is opened, the original script will not continue until the new shell is closed.

To fix, try:

In a shell script, try:

 su <username> -c "my command" 

So, if the user was "userA":

 su userA -c "mkdir /opt/D3GO/" 

However, if you use userA and you want to run the script part as root, you will be prompted to pass the pass.

 su root -c "mkdir /opt/D3GO/" 

You can also get around this by simply running the script with sudo first

 sudo ./myScript.sh 

Thus, the script saves the original user inside the script, which you can access using standard variables such as $ {USERNAME} , $ {UID} , etc.

Depending on what is best for you.

+1
source

Source: https://habr.com/ru/post/971935/


All Articles