Skip to main content
Tweeted twitter.com/StackUnix/status/1069199618813149187
Rollback to Revision 1
Source Link
filbranden
  • 22.6k
  • 4
  • 65
  • 87

NOTE: This is not really a duplicate of How to use shell wildcards with sudo? or other questions about running a shell under sudo. This question is really about why using sudo -s for this purpose doesn't work. From reading the man page of sudo, it seems that should work, but it actually doesn't. The motivation for this question was this answer in which I suggested using sudo -s, but it turns out that doesn't work.


When using sudo -s (short for the "--shell" option), it is possible to pass "sudo" a command, in which case it will run the command in a shell started by "sudo" as the target user.

NOTE: This is not really a duplicate of How to use shell wildcards with sudo? or other questions about running a shell under sudo. This question is really about why using sudo -s for this purpose doesn't work. From reading the man page of sudo, it seems that should work, but it actually doesn't. The motivation for this question was this answer in which I suggested using sudo -s, but it turns out that doesn't work.


When using sudo -s (short for the "--shell" option), it is possible to pass "sudo" a command, in which case it will run the command in a shell started by "sudo" as the target user.

When using sudo -s (short for the "--shell" option), it is possible to pass "sudo" a command, in which case it will run the command in a shell started by "sudo" as the target user.

Add a note indicating why I believe this is not a duplicate
Source Link
filbranden
  • 22.6k
  • 4
  • 65
  • 87

NOTE: This is not really a duplicate of How to use shell wildcards with sudo? or other questions about running a shell under sudo. This question is really about why using sudo -s for this purpose doesn't work. From reading the man page of sudo, it seems that should work, but it actually doesn't. The motivation for this question was this answer in which I suggested using sudo -s, but it turns out that doesn't work.


When using sudo -s (short for the "--shell" option), it is possible to pass "sudo" a command, in which case it will run the command in a shell started by "sudo" as the target user.

When using sudo -s (short for the "--shell" option), it is possible to pass "sudo" a command, in which case it will run the command in a shell started by "sudo" as the target user.

NOTE: This is not really a duplicate of How to use shell wildcards with sudo? or other questions about running a shell under sudo. This question is really about why using sudo -s for this purpose doesn't work. From reading the man page of sudo, it seems that should work, but it actually doesn't. The motivation for this question was this answer in which I suggested using sudo -s, but it turns out that doesn't work.


When using sudo -s (short for the "--shell" option), it is possible to pass "sudo" a command, in which case it will run the command in a shell started by "sudo" as the target user.

Source Link
filbranden
  • 22.6k
  • 4
  • 65
  • 87

"sudo -s <command>" runs command in a shell, but wildcards or metacharacters not working

When using sudo -s (short for the "--shell" option), it is possible to pass "sudo" a command, in which case it will run the command in a shell started by "sudo" as the target user.

(Similarly, sudo -i, also available as the "--login" option, also starts a shell and similarly accepts a command, which behaves the same way.)

Running commands in sudo via a shell can be important in many cases:

  • When using wildcards under a directory the current user doesn't have access to, but root does, the command needs to run under a root shell to have the wildcards properly expanded.
  • Running a whole pipeline, many commands chained in pipes (|).
  • When running a shell built-ins, such as for, if, etc. Running a small whole inline "script" under a single sudo can be useful.

The documentation of the "-s" option says (emphasis mine):

Run the shell specified by the SHELL environment variable if it is set or the shell specified by the invoking user's password database entry. If a command is specified, it is passed to the shell for execution via the shell's -c option. If no command is specified, an interactive shell is executed. Note that most shells behave differently when a command is specified as compared to an interactive session; consult the shell's manual for details.

In other words, when passing sudo -s a command, it is passed to the shell using the -c option, which takes a string with a "script" and then proceeds to execute it as a shell script.

The documentation doesn't really go much further on how to use this option, or to present examples, except to say "consult the shell's manual for details." This implies the command received is passed directly to the shell's -c option. However, as it turns out, that is not the case.

Passing it a shell script with multiple words fails:

$ sudo -s 'ls -ld /var/empty' /bin/bash: ls -ld /var/empty: No such file or directory 

The error message implies it's trying to run the whole string as a simple command... Hmmm, ok, so maybe add spaces would work? Yes that's the case:

$ sudo -s ls -ld /var/empty drwxr-xr-x. 3 root root 18 Jul 12 21:48 /var/empty 

That's not really how the shell's -c works though... Oh well, let's try to use some metacharacters, such as ~, which is a shortcut for the home directory, to see how this behaves. Note the ~ needs to be quoted, to prevent the non-sudo shell from expanding it (in which case it would expand to the home of the non-root user, rather than /root which is expected):

$ sudo -s ls '~' ls: cannot access '~': No such file or directory 

Ok, so that doesn't work, and the error output seems to imply the expansion is not happening, since it's preserving a literal ~ there.

What about wildcards? Not working either:

$ sudo -s ls '/root/*.cfg' ls: cannot access '/root/*.cfg': No such file or directory 

In both these cases, running the command with $SHELL -c works just fine. In this case, $SHELL is bash, so:

$ sudo bash -c 'ls ~' anaconda-ks.cfg $ sudo bash -c 'ls /root/*.cfg' /root/anaconda-ks.cfg 

One exception is that variables seem to work on sudo -s, such as:

$ sudo -s echo '$HOME' /root 

So:

  • What is going on here?
  • Why do wildcards and metacharacters such as ~ do not work on the command passed to sudo -s or sudo -i?
  • Given $SHELL -c takes a single string with a script, but sudo -s takes multiple arguments, how is the script assembled from the arguments?
  • What is a reliable way to run commands on a shell via sudo?