我想知道当我在脚本中使用subprocess
调用ssh-keygen
时是否需要做一些不同的事情。
我正在Linux环境中运行。
这是我的代码:
cfg_r = configparser.ConfigParser()
cfg_r.read('ssh_config.cfg')
p_mail=cfg_r.get('Company', 'mail')
bashCo m mand="ssh-keygen -t rsa -f /home/pi/.ssh/id_rsa - C \"{}\" -q -N \"\"".format(p_mail)
print(bashCommand.split())
proc = subprocess.Popen(bashCommand.split(),
stdout=subprocess.PIPE,
stderr=open('logfile_Get_conf.log', 'a'),
preexec_fn=os.setpgrp
)
outpu.stdout.read().decode('utf-8')
我使用configparser
来阅读除此之外的电子邮件,没有什么特别的。
bashCommand
应该是这样的:
ssh-keygen -t rsa -f /home/pi/.ssh/id_rsa -C "mail@gmail.com" -q -N ""
bashCommand.split()
也应该如此:
['ssh-keygen', '-t', 'rsa', '-f', '/home/pi/.ssh/id_rsa', '-C', '"mail@gmail.com"', '-q', '-N', '""']
非常奇怪的是,当我在 shell 中运行这个 bashCommand
时,没有出现任何问题:
ssh-keygen -t rsa -f /home/pi/.ssh/id_rsa -C "mail@gmail.com" -q -N ""
但是在我的日志文件中我仍然有这个错误:
Saving key "/home/pi/.ssh/id_rsa" failed: passphrase is too short (minimum five characters)
问题出在哪里?
最佳答案
我假设您正在类 Unix 环境中运行,并使用类似 bash
或类似的 shell(如变量 bashCommand
所暗示的那样)。 Windows 中的工作方式非常不同。
当您运行在 shell 中显示的命令时,作为 argv
传递给 ssh-keygen
的参数为(Python 语法):
['ssh-keygen', '-t', 'rsa', '-f', '/home/pi/.ssh/id_rsa', '-C', 'mail@gmail.com', '-q', '-N', '']
shell 展开字符串,并去掉所有引号。当您拆分命令时,参数将按原样传递,因为您没有为 Popen
指定 shell=True
。这意味着 ssh-keygen
的 argv
将是
['ssh-keygen', '-t', 'rsa', '-f', '/home/pi/.ssh/id_rsa', '-C', '"mail@gmail.com"', '-q', '-N', '""']
希望您能看到其中的差异。 -N
的参数不再为空。这是一个两个字符的字符串""
,显然少于五个字符。
您不需要字符串bashCommand
。使用列表要方便得多,然后直接将内容传递给 Popen
:
bashCommand = ['ssh-keygen', '-t', 'rsa', '-f', '/home/pi/.ssh/id_rsa', '-C', p_mail, '-q', '-N', '']
proc = subprocess.Popen(bashCommand, ...)
请注意,这样,您不需要对命令行进行任何字符串插值、花哨的分割、引用、转义或其他修改。
我曾提到过 Windows 上的工作方式非常不同。这是因为在 Windows 上,shell=True
始终被设置,并且您对此无能为力。 Windows 不会像 Unix 那样将 argv
传递给程序。相反,程序负责解析自己的命令行字符串,因此必须使用引号。使用 shell=True
通常会受到反对,因此我不建议使用它作为类 Unix 情况的解决方案(但它会起作用)。
正如评论中提到的,您的代码中还存在鲁棒性、可维护性和美观性方面的其他问题。但是,它们都不应阻止其正常运行。
关于python - 使用子进程调用时,ssh-keygen 会引发密码太短错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57167936/