Python 运行 作为用户和 sudo

Python run both as user and sudo

我正在编写一个 python 脚本来在我每次创建 VM 时自动安装一些工具,并且由于我不是 bash 粉丝,所以我使用 python。 问题是 apt 安装需要 sudo 权限,而 pip 安装不需要。

我正在寻找一种方法,在安装所有 apt 之后将我的权限降级回普通用户。

目前我尝试了像 os.system(f"su {user} && ...")subprocess.Popen(...)

这样的非常丑陋的内衬

有什么好的方法吗?

您可以将 apt 个命令列表与 subprocesspexpect 一起使用。如果没有使用 getpass:

提供密码,它也可以提示输入密码

NOTE - Tested on Ubuntu 20.04 using Python 3.8.10

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())

输出:

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