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
个命令列表与 subprocess
或 pexpect
一起使用。如果没有使用 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
我正在编写一个 python 脚本来在我每次创建 VM 时自动安装一些工具,并且由于我不是 bash 粉丝,所以我使用 python。
问题是 apt
安装需要 sudo 权限,而 pip
安装不需要。
我正在寻找一种方法,在安装所有 apt 之后将我的权限降级回普通用户。
目前我尝试了像 os.system(f"su {user} && ...")
或 subprocess.Popen(...)
有什么好的方法吗?
您可以将 apt
个命令列表与 subprocess
或 pexpect
一起使用。如果没有使用 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