0

I have a little maintenance thing to do as super user, from time to time. I would like that to be a one-liner, for easy copying from my self-documentation to a terminal. I reduced it to the bare essentials of where it goes wrong; it involves setting and using a shell variable. See for yourselves:

$ sudo bash -c 'var=VAL; echo "$USER $UID $HOME ** $var **"; declare -p var;'
root 0 /home/myuser ** VAL **
declare -- var="VAL"

You'll of course notice that I didn't give sudo it's -i option, and therefor the HOME variable was inapropriate. So I repeated the command with sudo -i:

$ sudo -i bash -c 'var=VAL; echo "$USER $UID $HOME ** $var **"; declare -p var;'
root 0 /root **  **
declare -- var="VAL"

And there it is: although declare declares that var does have the value VAL assigned to it, echo does not echo it. How can that be?

And by the way, I tried the same command, but starting with declare -p var; ..., to make sure var did not double with some read-only environment or shell special variable; it gives bash: line 0: declare: var: not found, as expected.

For completeness I did the same in a multiliner: opening a proper shell prompt and typing several command lines:

$ sudo -i bash
[sudo] password for myuser:
# var=VAL
# echo "$USER $UID $HOME ** $var **"
root 0 /root ** VAL **

This works as it should be, except that I have to copy and paste line by line.

Can anyone explane why, in the one-liner with sudo -i bash -c, a variable can be set, and is declared to be set, but expands to nothing?

$ sudo --version
Sudo version 1.8.21p2
Sudoers policy plugin version 1.8.21p2
Sudoers file grammar version 46
Sudoers I/O plugin version 1.8.21p2
$ bash --version
GNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu)

But here is what @terdon asked, and I never tinkered with that:

$ sudo grep '^[^#].' /etc/sudoers
[sudo] password for myuser: 
Defaults    env_reset
Defaults    mail_badpass
Defaults    secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"
root    ALL=(ALL:ALL) ALL
%admin ALL=(ALL) ALL

A similar question here on StackExchange explains the unexpected behaviour, as was the question: sudo -i starts an extra shell first, in comparison with plain sudo, and it is that extra shell that first interprets the bash -c 'command ...' as a string, encountering the same problems you will have when you try to insert a plain string containing $'s and`'s into a command.

So I took the super user thing a step further, and added su to the command to make it do what I want it to do; mostly you will want to use su --version, but the su-version in this case works fine too:

$ sudo su - root -c 'var=VAL; echo "$USER $UID $HOME ** $var **"; declare -p var;'
root 0 /root ** VAL **
declare -- var="VAL"

$ sudo su root -c 'var=VAL; echo "$USER $UID $HOME ** $var **"; declare -p var;'
root 0 /root ** VAL **
declare -- var="VAL"
9
  • That's weird. Your first command should have worked as expected. On my system, sudo bash -c 'var=VAL; echo "$USER $UID $HOME ** $var **";' prints root 0 /root ** VAL ** as expected. Have you perhaps aliased sudo to sudo -E? What's the output of type sudo? If not, please share the output of sudo grep '^[^#].' /etc/sudoers. You must be telling it to keep the $HOME variable. Commented Dec 3 at 12:15
  • Also, there is no need to copy line by line. You can copy multiple lines into the terminal and then execute them all when you press enter. Even without pressing enter if you disable bracketed paste. Commented Dec 3 at 12:17
  • @terdon No aliases here; I prefer to give an alias a distinct name. $ type sudo gives sudo is /usr/bin/sudo. And about the HOME variable, in the 10 years that I do linux, I have never known other that to need sudo -i to have it set to /root. I'll add the sudo grep thing to the question, I can't format multiline here in the comments. Commented Dec 3 at 12:40
  • I can't imagine why though. I mean, unless you actively export HOME, it should always be reset to the home dir of the user you switched to. Are you on Ubuntu, perhaps? I think they do some weird things. Commented Dec 3 at 12:44
  • @terdon I try to avoid copy- and pasting multiple lines, because my documentation files use tabbed indentation. Pasting these in bash triggers unwanted command completion. Commented Dec 3 at 12:44

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.