sudo command behaviour difference with the -i flag

46 Views Asked by At

I intend to write a shell wrapper for the sudo command together with the full login context of the root account. I encountered the issue that the dollar character disappeared or interpreted somewhere if I invoked the sudo command with the -i flag.

When I execute the command sudo -n /bin/printf "%s\n" '$a' I get as output:

$a

When I execute the command sudo -i -n /bin/printf "%s\n" '$a' I get an empty line as output.

For the second case I was expecting the same output as for the first command. Am I wrong in my expectation? If yes, what is the appropriate way to escape the dollar character to match the output of the first command?

1

There are 1 best solutions below

2
knittl On

From man sudo

-i, -‐login

Run the shell specified by the target user's password database entry as a login shell. This means that login- specific resource files such as .profile, .bash_profile, or .login will be read by the shell. If a command is specified, it is passed to the shell as a simple command using the -c option. The command and any args are concatenated, separated by spaces, after escaping each character (including white space) with a backslash (‘\’) except for alphanumerics, underscores, hyphens, and dollar signs.

So sudo /bin/printf "%s\n" '$a' runs printf directly with two arguments (%s\n and $a) and printf doesn't know anything about shell variables, therefore prints them unexpanded.

On the other hand:

sudo -i /bin/printf "%s\n" '$a'

Forks a new shell (the user's login shell) and then passes the command and the args. Characters »except for alphanumerics, underscores, hyphens, and dollar signs are escaped«. So you end up with sudo executing the following:

/bin/sh -c '/bin/printf %s\n $a'

The shell then executes the command

/bin/printf %s\n $a

which means it will expand the parameter before passing it to printf.