用Python中的Popen在Cron和命令行运行时返回不同的输出

3
我在使用Python脚本时遇到了奇怪的问题。当我通过命令行运行它(python /home/myname/myscriptname.py),它返回了我期望的正确值。
这是我的cron命令- 10 * * * * /usr/bin/python /home/myname/myscriptname.py 当通过cron运行时,我得到以下输出(不正确)-
('', None)
Module not enabled

当我通过命令行运行它时,我得到了以下(正确的)结果 -
The following people have the module enabled: 
person1
person2
person3

怎么回事?我已经尝试使用完整路径调用每个命令(没有结果),并在crontab中添加以下内容 -

PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin,但是没有变化。问题可能出在哪里?当以拥有crontab的相同用户身份运行脚本时,它可以正常工作。

#!/usr/bin/python
import sys, os, subprocess

command = '/usr/local/bin/drush --alias-path=/data/scripts/drush_aliases @staging pml -y | /bin/grep -i dblog | /bin/grep -i enabled'


#Module Check
try:
   process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None, shell=True)

   output2 = process.communicate()
   print output2
   if output2[0] == "":
      staging_return = "Module not enabled"
   else:
      staging_return = "The following people have the module enabled: \n" + output2[0]
   print staging_return

except Exception as E:
   print E
   print "Command failed"

编辑 - 这里是每个环境中os.environ的输出 -

这是在cron中os.environ的输出 -

{'LANG': 'en_US.UTF-8', 'SHELL': '/bin/sh', 'SHLVL': '1', 'PWD': '/home/myuser', 'LOGNAME': 'myuser', 'USER': 'myuser', 'HOME': '/home/myuser', 'PATH': '/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin', '_': '/usr/bin/python'}

终端输出是 -
{'LESSOPEN': '||/usr/bin/lesspipe.sh %s', 'CVS_RSH': 'ssh', 'LOGNAME': 'myuser', 'USER': 'myuser', 'QTDIR': '/usr/lib64/qt-3.3', 'PATH': '/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin', 'LANG': 'en_US.UTF-8', 'TERM': 'xterm', 'SHELL': '/bin/bash', 'SHLVL': '2', 'G_BROKEN_FILENAMES': '1', 'HISTSIZE': '1000', 'SUDO_USER': 'myuser', 'HOME': '/home/myuser', 'USERNAME': 'root', 'SUDO_UID': '860', '_': '/usr/bin/python', 'SUDO_COMMAND': '/bin/su', 'SUDO_GID': '860', 'HOSTNAME': 'MYHOSTNAME', 'PWD': '/home/myuser', 'MAIL': '/var/spool/mail/myuser', 

这可能是因为cron以root身份而不是本地用户身份运行您的脚本。如果您在命令行中使用sudo运行脚本,会有什么输出? - undefined
你可以尝试切换使用的shell:在你的Popen调用中添加executable='/bin/bash',因为默认的cron shell是sh。另外,请检查用户登录时的env与脚本运行时的env是否有差异。可能会有其他随机设置(例如,有时是PYTHONPATH)。 - undefined
定时任务没有设置为root用户,当我尝试以root身份运行它时失败了(无法进行ssh连接)。由于它能够连接到其他服务器,我相当确定这部分是正常工作的。在Popen调用中添加executable='/bin/bash'并没有改变其行为。 - undefined
我已经编辑了原始问题,将每个环境中的变量包含在内。 - undefined
你是否有一些环境变量(除了Path之外)对用户定义的命令产生影响?你可以尝试一下:'. '~/.bashrc; /usr/local/bin/drush --alias-path=/data/scripts/drush_aliases @staging pml -y | /bin/grep -i dblog | /bin/grep -i enabled' - undefined
显示剩余3条评论
1个回答

0

进行了更多的研究后,我找到了问题所在。

有两个问题。第一个问题出现在命令变量中 -

command = '/usr/local/bin/drush --alias-path=/data/scripts/drush_aliases @staging pml -y | /bin/grep -i dblog | /bin/grep -i enabled'

这个命令需要拆分成一个列表,然后将列表作为一个整体命令传递给Popen。我的命令变量变成了这样 -

command = ['/usr/local/bin/drush', '--alias-path=/data/scripts/drush_aliases', '@staging', 'pml', '-y'](对其他管道语句也做同样处理)。

在进行了这个更改之后,我的命令在process.communicate上挂起了。为了解决这个问题,我必须在Popen调用中添加一个stdin参数。带有此参数的新Popen调用如下所示 -

process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=None, stdin=subprocess.PIPE)(由于我不再将语句以一个长的bash命令进行管道传递,因此去掉了shell=True)。

而是采用以下方式代替从一个命令传递输出到另一个命令 -

command2 = ['/bin/grep', '-i', 'dblog']
command3 = ['/bin/grep', '-i', 'enabled']
process2 = subprocess.Popen(command2, stdin=process.stdout, stdout=subprocess.PIPE)
process3 = subprocess.Popen(command3, stdin=process2.stdout, stdout=subprocess.PIPE)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接