繁体   English   中英

使用subprocess.communicate()的线程抛出错误:b'standard in必须是tty \\\\ n'

[英]Thread using subprocess.communicate() throws the error: b'standard in must be a tty\\n'

我在使用Python中的Thread中的subprocess.Popen()调用脚本时遇到问题。 我尽可能多地添加了细节。 如果我需要在问题中添加更多详细信息,请告知我们。 任何帮助是极大的赞赏。 提前致谢。

TL:DR subprocess.Popen()期待stdin并抛出错误“tandard in must be tty”,即使调用的脚本不需要任何stdin。 此问题开始出现,因为在调用脚本时使用了“su userName -c”

细节

我正在使用django开发一个Web应用程序,它在后端执行PERL脚本。 我正在以root用户身份部署应用程序,我打算以触发它的用户身份运行脚本。 我将从我们页面中的用户那里获取userName。

初始命令测试:我以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

错误:b'standard in必须是tty \\ n'在pipe.communicate()中被抛出

我已经明确提到stdin将是None。 但我不明白为什么子进程仍然需要一些输入。

观察:

  1. 发生在那里我尝试使用 [pipe.communicate()],并运行上述命令的地方的问题。
  2. 当我删除“su username -c”部分时,上面的命令通过子进程执行而没有任何问题,如下所示。 但这不是预期的功能,所以我必须以触发它的用户身份运行它。

    没有“su userName -c”部分的示例命令:

    /path_to_my_script/reImage.pm --host abcdefg --version 1.2.3.5000

  3. 由于添加了“su userName -c”,因此问题开始出现。

  4. 我已经知道子进程正在期待stdin,因此即使不调用命令也会抛出错误。
  5. 当我从终端运行它而不接受/提示输入/ stdin时,脚本以指定用户身份运行。一旦调用它就不需要任何stdin但我不理解为什么subprocess.communicate()期望我提供输入。

我试过以下:

  1. 我在pipe.communicate()没有输入的情况下尝试过相同的函数,但它会抛出相同的错误。
  2. 我尝试过stdin = subprocess.PIPE和pipe.communicate(input ='\\ n')。 我试图将新行作为标准输入,但它会抛出相同的错误。
  3. 尝试使用subprocess.call()甚至抛出相同的错误。
  4. 不能使用os.system(命令),因为我需要分析输出。 如果subprocess.Popen()根本不起作用,则将输出写入文件可能是一种解决方法。

谢谢你的耐心和阅读,直到最后,

我找到了解决问题的方法。

最初,当我尝试从终端使用以下内容时,

sudo -u userName command

我无法执行,因为我遇到了“权限被拒绝”错误。 所以后来我开始从终端使用以下命令

su userName -c "command"

这个su命令在终端上运行良好。 现在是时候在我的Web应用程序中使用它来通过subprocess.invoke(命令)在系统上调用此命令,这就是我得到“标准必须是tty”错误的地方。

我在评论中跟随了@Ryan给出的链接,并在/ etc / sudoers文件中更改了root用户的requiretty,如下所示,这也无济于事。

Defaults:root !requiretty

最后,当我评论“Defaults:requiretty”时(我知道这可能会引起安全问题,但它对于这个应用程序来说很有用)并且在subprocess.invoke ()中使用了su -userName命令 ,它按预期工作。 现在我能够以请求的用户身份运行脚本。

谢谢阅读,

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM