简体   繁体   English

Python 同时作为用户和 sudo 运行

[英]Python run both as user and sudo

I'm writing a python script to automatize the installation of some tools every time I create a VM and, since I'm not a bash fan I'm doing it with python.我正在编写一个 python 脚本,以便在每次创建 VM 时自动安装一些工具,并且由于我不是 bash 粉丝,所以我正在使用 python 来完成它。 The problem is that apt installations require sudo privileges, while pip installations don't.问题是apt安装需要 sudo 权限,而pip安装不需要。

I'm looking for a way to downgrade my privileges back to normal user's after all apt installations.在所有 apt 安装之后,我正在寻找一种将我的权限降级回普通用户的方法。

At the moment I tryed a pretty ugly oneliner like os.system(f"su {user} && ...") or subprocess.Popen(...)目前我尝试了一个非常丑陋的单行器,比如os.system(f"su {user} && ...") subprocess.Popen(...)

Is there a decent way?有没有靠谱的方法?

You can use a list of apt commands with subprocess or pexpect .您可以将apt命令列表与subprocesspexpect It can also prompt for a password if no password is provided using getpass :如果使用getpass未提供密码,它也可以提示输入密码:

NOTE - Tested on Ubuntu 20.04 using Python 3.8.10注意- 使用 Python 3.8.10 在 Ubuntu 20.04 上测试

NOTE - Updated to use and test pipes.quote - Thx, pts!注意- 更新为使用和测试管道。引用 - 谢谢,点!

import pipes
import shlex
import subprocess
from getpass import getpass

import pexpect

sudo_password = '********'
# First command in double quotes to test pipes.quote - Thx, pts!
commands = ["apt show python3 | grep 'Version'",
            'sudo -S apt show python3 | grep Version', ]

print('Using subprocess...')
for c in commands:
    c = str.format('bash -c {0}'.format(pipes.quote(c)))
    # Use sudo_password if not None or empty; else, prompt for a password
    sudo_password = (
            sudo_password + '\r'
    ) if sudo_password and sudo_password.strip() else getpass() + '\r'
    p = subprocess.Popen(shlex.split(c), stdin=subprocess.PIPE,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE, universal_newlines=True)
    output, error = p.communicate(sudo_password)
    rc = p.returncode
    if rc != 0:
        raise RuntimeError('Unable to execute command {0}: {1}'.format(
            c, error.strip()))
    else:
        print(output.strip())

print('\nUsing pexpect...')
for c in commands:
    c = str.format('bash -c {0}'.format(pipes.quote(c)))
    command_output, exitstatus = pexpect.run(
        c,
        # Use sudo_password if not None or empty; else, prompt for a password
        events={
            '(?i)password': (
                    sudo_password + '\r'
            ) if sudo_password and sudo_password.strip() else (
                    getpass() + '\r')
        },
        withexitstatus=True)
    if exitstatus != 0:
        raise RuntimeError('Unable to execute command {0}: {1}'.format(
            c, command_output))
    # For Python 2.x, use string_escape.
    # For Python 3.x, use unicode_escape.
    # Do not use utf-8; Some characters, such as backticks, may cause exceptions
    print(command_output.decode('unicode_escape').strip())

Output:输出:

Using subprocess...
Version: 3.8.2-0ubuntu2
Version: 3.8.2-0ubuntu2

Using pexpect (and getpass)...

Version: 3.8.2-0ubuntu2
[sudo] password for stack: 

Version: 3.8.2-0ubuntu2

Process finished with exit code 0

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM