Python 使用subprocess.communicate()的线程抛出错误:b';中的标准必须是tty\\n';

Python 使用subprocess.communicate()的线程抛出错误:b';中的标准必须是tty\\n';,python,python-2.7,python-3.x,django-views,subprocess,Python,Python 2.7,Python 3.x,Django Views,Subprocess,我在Python线程中使用subprocess.Popen()调用脚本时遇到问题。我已经尽可能多地添加了细节。请让我知道,如果我需要添加更多的细节问题。非常感谢您的帮助。提前谢谢 TL:DR subprocess.Popen()需要stdin并抛出错误“standard in必须是tty”,即使调用的脚本不需要任何stdin。这个问题从调用脚本时使用“su userName-c”开始出现 详细信息 我正在使用django开发一个web应用程序,它在后端执行PERL脚本。我正在以root用户的身份

我在Python线程中使用subprocess.Popen()调用脚本时遇到问题。我已经尽可能多地添加了细节。请让我知道,如果我需要添加更多的细节问题。非常感谢您的帮助。提前谢谢

TL:DR subprocess.Popen()需要stdin并抛出错误“standard in必须是tty”,即使调用的脚本不需要任何stdin。这个问题从调用脚本时使用“su userName-c”开始出现

详细信息

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

初始命令测试:我以root用户身份登录,并使用以下命令以用户身份启动脚本:

su userName -c ' /path_to_my_script/reImage.pm --host abcdefg --version 1.2.3.5000' 
当我在以root用户身份登录的终端中调用它时,上面的操作与预期一样正常,并以指定的用户身份运行。所以我知道上面的命令没有问题

工作流程:

当用户给出输入并在网页中提交时,我启动后台程序线程,在后台调用上述命令。调用命令后,perl脚本完成任务并返回结果

我在views.py中使用以下代码创建线程(注意:我只编写与问题相关的代码行,而不是views.py的完整内容)

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'被抛出管道。communicate()

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

观察结果:

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

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

    /指向我的脚本/reImage.pm的路径——主机abcdefg——版本1.2.3.5000

  • 自从添加了“su userName-c”之后,这个问题就开始出现了

  • 我知道子进程需要一个stdin,因此即使不调用命令也会抛出一个错误
  • 当我从终端运行脚本时,脚本以指定用户的身份运行,而不接受/提示输入/stdin。调用脚本后,它不需要任何stdin,但我不理解subprocess.communicate()为什么希望我提供输入 我尝试了以下方法:

  • 我在pipe.communicate()上没有输入的情况下尝试了相同的函数,但它抛出了相同的错误
  • 我尝试使用stdin=subprocess.PIPE和PIPE.communicate(输入='\n')。我试图将新行命名为stdin,但它抛出了相同的错误
  • 尝试使用subprocess.call(),即使这会引发相同的错误
  • 无法使用os.system(命令),因为我需要分析输出。如果subprocess.Popen()根本不起作用,将输出写入文件可能是一种解决方法
    感谢您的耐心和阅读,直到最后,

    我找到了解决问题的方法

    最初,当我尝试从终端使用以下命令时

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

    su userName -c "command"
    
    这个su命令在终端上运行良好。现在是时候在我的web应用程序中使用它,通过子流程在系统上调用这个命令了。invoke(command),这就是我得到“标准输入必须是tty”错误的地方

    我遵循了@Ryan在评论中给出的链接,并将root用户/etc/sudoers文件中的要求更改为以下内容,这也没有帮助

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


    感谢阅读,

    我找到了解决问题的方法

    最初,当我尝试从终端使用以下命令时

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

    su userName -c "command"
    
    这个su命令在终端上运行良好。现在是时候在我的web应用程序中使用它,通过子流程在系统上调用这个命令了。invoke(command),这就是我得到“标准输入必须是tty”错误的地方

    我遵循了@Ryan在评论中给出的链接,并将root用户/etc/sudoers文件中的要求更改为以下内容,这也没有帮助

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


    感谢阅读,

    也许你应该使用pexpect@Ааааааааааааааааааааа:我尝试过使用也许你应该使用pexpect@Аааааааааааааааааааааа