python3 - subprocess with sudo to >> append to /etc/hosts

2.2k views Asked by At

I've been wrestling with solutions from "How do I use sudo to redirect output to a location I don't have permission to write to?" and "append line to /etc/hosts file with shell script" with no luck.

I want to "append 10.10.10.10 puppetmaster" at the end of /etc/hosts. (Oracle/Red-Hat linux).

Been trying variations of:

subprocess.call("sudo -s", shell=True)

subprocess.call('sudo sh -c" "10.10.10.10 puppetmaster" >> /etc/hosts"', shell=True)

subprocess.call(" sed -i '10.10.10.10 puppetmaster' /etc/hosts", shell=True)

But /etc/hosts file stands still. Can someone please point out what I'm doing wrong?

4

There are 4 answers

12
Padraic Cunningham On BEST ANSWER

You can do it in python quite easily once you run the script with sudo:

with open("/etc/hosts","a") as f:
    f.write('10.10.10.10 puppetmaster\n')

opening with a will append.

2
Alfe On

The problem you are facing lies within the scope of the sudo.

The code you are trying calls sudo with the arguments sh and -c" "10.10.10.10 puppetmaster". The redirection of the >> operator, however, is done by the surrounding shell, of course with its permissions.

To achieve the effect you want, try starting a shell using sudo which then is given the command:

sudo bash -c 'sh -c" "10.10.10.10 puppetmaster" >> /etc/hosts"'

This will do the trick because the bash you started with sudo has superuser permissions and thus will not fail when it tries to perform the output redirection with >>.

To do this from within Python, use this:

subprocess.call("""sudo bash -c 'sh -c" "10.10.10.10 puppetmaster" >> /etc/hosts"'""", shell=True)

But of course, if you run your Python script with superuser permissions (start it with sudo) already, all this isn't necessary and the original code will work (without the additional sudo in the call):

subprocess.call('sh -c" "10.10.10.10 puppetmaster" >> /etc/hosts"', shell=True)
7
Charles Duffy On

If you weren't escalating privileges for the entire script, I'd recommend the following:

p = subprocess.Popen(['sudo', 'tee', '-a', '/etc/hosts'],
                     stdin=subprocess.PIPE, stdout=subprocess.DEVNULL)
p.stdin.write(b'10.10.10.10 puppetmaster\n')
p.stdin.close()
p.wait()

Then you can write arbitrary content to the process's stdin (p.stdin).

2
Daniel On

Simply use dd:

subprocess.Popen(['sudo', 'dd', 'if=/dev/stdin',
    'of=/etc/hosts', 'conv=notrunc', 'oflag=append'],
    stdin=subprocess.PIPE).communicate("10.10.10.10 puppetmaster\n")