【发布时间】:2017-08-05 14:41:32
【问题描述】:
我在 Python 的线程中使用 subprocess.Popen() 调用脚本时遇到问题。我已经添加了尽可能多的细节。如果我需要为问题添加更多详细信息,请告诉我。任何帮助是极大的赞赏。提前致谢。
TL:DR subprocess.Popen() 期待标准输入并抛出错误“标准输入必须是 tty”,即使调用的脚本不需要任何标准输入。由于在调用脚本时使用了“su userName -c”,因此开始出现此问题
详情
我正在使用 django 开发一个在后端执行 PERL 脚本的 Web 应用程序。我以 root 用户身份部署应用程序,并打算以触发它的用户身份运行脚本。我将从我们页面中的用户那里获取用户名。
初始命令测试:我以 root 身份登录,并使用以下命令以用户身份启动脚本:
su userName -c ' /path_to_my_script/reImage.pm --host abcdefg --version 1.2.3.5000'
当我在以 root 用户身份登录的终端中调用它时,上述内容按预期工作并以指定的用户身份运行。所以我知道上面的命令没有问题。
工作流程:
当用户提供输入并在网页中提交时,我会启动一个后台线程来调用上述命令。一旦命令被调用,perl 脚本就会完成它的任务并返回结果。
我在 views.py 中使用以下代码创建线程(注意:我只编写与问题相关的代码行,而不是 views.py 的完整内容)
from threading import Thread
reImageThread = Thread(name = hostName, target = reImageFunction ,args = (hostName,buildNumber,userName) )
reImageThread.daemon = True
reImageThread.start()
reImageFunction 在另一个文件中定义如下:
import subprocess
def reImageFunction(hostName,buildNumber,userName):
command = " /path_to_my_script/reImage.pm --host "+str(hostName)+" --version "+str(buildNumber)+" " #Blank space at the end is added intentionally
command = " su " + userName + " -c \' " + command + " \' "
print(command) #printing for debugging
#The final command composed would of the format shown in the begenning of this question.
pipe = subprocess.Popen(command , stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
(result,err) = pipe.communicate()
print(err) #Printing the err for debugging
.... #Processing the result
.... #Processing the result
在 pipe.communicate() 中抛出错误:b'standard in must be a tty\n'
我已经明确提到标准输入将是无。但我不明白为什么子进程仍然需要一些输入。
观察:
- 问题出现在我尝试使用 subprocess [pipe.communicate() ] 并运行上述命令的地方。
-
当我删除“su username -c”部分时,上面的命令是通过subprocess执行的,没有任何问题,示例如下所示。但这不是预期的功能,所以我必须以触发它的用户身份运行它。
不带“su userName -c”部分的示例命令:
/path_to_my_script/reImage.pm --host abcdefg --version 1.2.3.5000
自从添加了“su userName -c”后,问题开始出现。
- 我知道子进程需要一个标准输入,因此即使没有调用命令也会引发错误。
- 当我从终端运行脚本时,该脚本以指定用户身份运行,而不需要/提示输入/stdin。一旦调用它就不需要任何标准输入,但我不明白为什么 subprocess.communicate() 期望我提供输入.
我尝试了以下方法:
- 我在 pipe.communicate() 没有输入的情况下尝试了相同的功能,但它会引发相同的错误。
- 我尝试使用 stdin=subprocess.PIPE 和 pipe.communicate(input='\n')。我试图将新行作为标准输入,但它引发了同样的错误。
- 尝试使用 subprocess.call() 即使会引发相同的错误。
- 无法使用 os.system(command),因为我需要分析输出。如果 subprocess.Popen() 根本不起作用,将输出写入文件可能是一种解决方法。
感谢您的耐心阅读到最后,
【问题讨论】:
-
也许你应该使用 pexpect pexpect.sourceforge.net/pexpect.html
-
@АндрейЧереваткин:我尝试使用它,但它在我的情况下不起作用,所以不得不使用子进程。
-
@Ryan:非常感谢,那个指针有帮助! :)
标签: python python-2.7 python-3.x django-views subprocess