Mic*_*wol 6 python shell command-line
我一直在尝试在另一个python脚本中运行脚本而没有运气.
我试图运行的脚本是garminbackup.py,可以在以下repo中找到.
https://github.com/petergardfjall/garminexport
当您从命令行运行此脚本时,它会要求您提供一些信息,用户名,保存文件的位置等等...
command = 'python garminbackup.py --backup-dir=Name email --format tcx'
Run Code Online (Sandbox Code Playgroud)
然后它要求输入密码,一旦输入密码,就开始将garmin文件下载到提供的目录中.我的目标是创建一个程序,它循环遍历多个帐户并更新每个文件夹中的数据.
我的问题是我似乎无法在python中获得子进程模块来实现这一点.
我没有运气就尝试了以下命令.它似乎卡在输入密码输入屏幕上,并没有做任何其他事情.
import subprocess,shlex
from subprocess import PIPE,call
import os
p = subprocess.Popen(command,stdout=subprocess.PIPE,stdin=subprocess.PIPE,shell=True)
p.stdin.write("password\n")
p.wait()
Run Code Online (Sandbox Code Playgroud)
我搜索了几个小时,运气不好.任何帮助表示赞赏.
尽管OP通过使用该--password选项解决了这个问题,但其他人可能会偶然发现同样的问题,并且正如HuStmpHrr已经指出的那样,在命令行中传递密码不是一个好主意。
在本例中,被调用的脚本garminbackup.py使用getpass。正如文档中所暗示的, getpass 的实现比仅仅读取 stdin 更复杂:
[...] 在 Unix 上,提示符被写入类似文件的对象流中。流默认为控制终端 (/dev/tty),或者如果 sys.stderr 不可用(此参数在 Windows 上被忽略)。
如果无回显输入不可用,则 getpass() 会回退到打印警告消息以进行流式传输并从 sys.stdin 读取并发出 GetPassWarning。
我们可以模拟一个虚拟终端,但如果没有库,那就太复杂了(参见下一章)。
另一种方法是删除存在终端的信息(“如果无回声输入不可用”)。结果比我预期的要难,通常运行一个命令cat | command | cat应该摆脱 tty 检测,但似乎 getpass 改变其行为要么太聪明,要么太无知。
正如LohmarASHAR 已经提到的,如果您可以使用pexpect ( pip install pexpect),您就应该使用。它正是为此而设计的,并将涵盖所有极端情况。
例如:
Run Code Online (Sandbox Code Playgroud)child = pexpect.spawn('scp foo user@example.com:.') child.expect('Password:') child.sendline(mypassword)这甚至适用于要求密码或 普通 stdio 流之外的其他输入的命令。例如,ssh 直接从 TTY 设备读取输入,绕过 stdin。
继续使用 OP 的示例,但使用 pexpect:
#!/usr/bin/env python
import pexpect
command = 'python garminbackup.py --backup-dir=Name email --format tcx'
p = pexpect.spawn(command) # instead of subprocess.Popen
p.expect(":") # This is waiting for the prompt "Enter password:", but I rather only use ":" to cope with internationalisation issues
p.sendline("password")
print p.read() # Output the sub-processes output
p.wait()
Run Code Online (Sandbox Code Playgroud)