如何使用 Python 使用 Unix pass 命令行程序自动设置密码
How can I use Python to automate setting a password using the Unix pass command line program
我正在尝试使用 Unix pass 程序自动设置新密码。
我知道有一个 Python 库 pexpect 可能会有所帮助,但我想避免使用第三方库。
使用终端时,流程如下所示:
$ pass insert --force gmail
>> Enter password for gmail: <type in password using masked prompt>
>> Retype password for gmail: <reenter password>
我希望我的函数做什么:
- 运行命令
pass insert --force {entry_name}
- 捕获输出(并回显以进行测试)
- 检查输出是否存在 'password for gmail',如果为真
- 将'{password}\n'写入标准输入
- 再次将'{password}\n'写入标准输入
- 回显任何错误或消息以进行测试
问题:
我卡在了第 2 步。子进程无限期挂起、超时并出现错误,或者不产生任何输出。
尝试次数:
- 我尝试过使用 stdin.write() 和 communicate() 配置 Popen()。
- 我在不同的点设置了 wait() 调用。
- 我已经尝试了 shell=True 和 shell=False 选项(出于安全原因更喜欢 False)
代码:
def set_pass_password(entry_name, password):
from subprocess import Popen, PIPE
command = ['pass', 'insert', '--force', entry_name]
sub = Popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines=True)
# At this point I assume that the command has run, and that there is an "Enter password..." message
message = sub.stdout.read() # also tried readline() and readlines()
print(message) # never happens, because process hangs on stdout.read()
if 'password for {}'.format(entry_name) in message:
err, msg = sub.communicate(input='{p}\n{p}\n'.format(p=password))
print('errors: {}\nmessage: {}'.format(err, msg))
编辑:原来的答案是关于 passwd
,这是用来 设置 密码的。我最近注意到您使用 pass
,这是一个密钥库(实际上并没有更改 Unix 密码)。 pass
程序的工作方式不同,如果 stdin
不是 tty, 将不会 打印提示。因此,以下非常简单的程序有效:
def set_pass_password(entry_name, password):
from subprocess import Popen, PIPE
command = ['pass', 'insert', '--force', entry_name]
sub = Popen(command, bufsize=0, stdin=PIPE, stdout=PIPE, stderr=PIPE)
err, msg = sub.communicate(input='{p}\n{p}\n'.format(p=password))
print('errors: {}\nmessage: {}'.format(err, msg))
if __name__ == "__main__":
set_pass_password("ttt", "ttt123asdqwe")
(如果命令成功,你会看到 stderr 和 stdout 都是空的)。
对于passwd
命令:
仅供参考:passwd
命令将提示输出到 stderr
,而不是 stdout
。
注意:与其在同一个 'write' 中发送两次密码,您 可能 需要等待第二次提示才能再次发送密码。
对于这种简单的情况,与您的代码类似的代码应该可以工作,但通常您应该在所有管道上使用 select
并在另一端准备好时使用 send/receive 数据,所以您不需要不会出现死锁。
我正在尝试使用 Unix pass 程序自动设置新密码。 我知道有一个 Python 库 pexpect 可能会有所帮助,但我想避免使用第三方库。
使用终端时,流程如下所示:
$ pass insert --force gmail
>> Enter password for gmail: <type in password using masked prompt>
>> Retype password for gmail: <reenter password>
我希望我的函数做什么:
- 运行命令
pass insert --force {entry_name}
- 捕获输出(并回显以进行测试)
- 检查输出是否存在 'password for gmail',如果为真
- 将'{password}\n'写入标准输入
- 再次将'{password}\n'写入标准输入
- 回显任何错误或消息以进行测试
问题:
我卡在了第 2 步。子进程无限期挂起、超时并出现错误,或者不产生任何输出。
尝试次数:
- 我尝试过使用 stdin.write() 和 communicate() 配置 Popen()。
- 我在不同的点设置了 wait() 调用。
- 我已经尝试了 shell=True 和 shell=False 选项(出于安全原因更喜欢 False)
代码:
def set_pass_password(entry_name, password):
from subprocess import Popen, PIPE
command = ['pass', 'insert', '--force', entry_name]
sub = Popen(command, stdin=PIPE, stdout=PIPE, stderr=PIPE, universal_newlines=True)
# At this point I assume that the command has run, and that there is an "Enter password..." message
message = sub.stdout.read() # also tried readline() and readlines()
print(message) # never happens, because process hangs on stdout.read()
if 'password for {}'.format(entry_name) in message:
err, msg = sub.communicate(input='{p}\n{p}\n'.format(p=password))
print('errors: {}\nmessage: {}'.format(err, msg))
编辑:原来的答案是关于 passwd
,这是用来 设置 密码的。我最近注意到您使用 pass
,这是一个密钥库(实际上并没有更改 Unix 密码)。 pass
程序的工作方式不同,如果 stdin
不是 tty, 将不会 打印提示。因此,以下非常简单的程序有效:
def set_pass_password(entry_name, password):
from subprocess import Popen, PIPE
command = ['pass', 'insert', '--force', entry_name]
sub = Popen(command, bufsize=0, stdin=PIPE, stdout=PIPE, stderr=PIPE)
err, msg = sub.communicate(input='{p}\n{p}\n'.format(p=password))
print('errors: {}\nmessage: {}'.format(err, msg))
if __name__ == "__main__":
set_pass_password("ttt", "ttt123asdqwe")
(如果命令成功,你会看到 stderr 和 stdout 都是空的)。
对于passwd
命令:
仅供参考:passwd
命令将提示输出到 stderr
,而不是 stdout
。
注意:与其在同一个 'write' 中发送两次密码,您 可能 需要等待第二次提示才能再次发送密码。
对于这种简单的情况,与您的代码类似的代码应该可以工作,但通常您应该在所有管道上使用 select
并在另一端准备好时使用 send/receive 数据,所以您不需要不会出现死锁。