【问题标题】:Python Popen shell script but failPython Popen shell脚本但失败
【发布时间】:2015-12-08 17:32:10
【问题描述】:

我要执行 bash 命令

 '/bin/echo </verbosegc> >> /tmp/jruby.log'

在 python 中使用 Popen。代码不会引发任何异常,但执行后 jruby.log 不会发生任何更改。 python代码如下所示。

>>> command='/bin/echo </verbosegc> >> '+fullpath
>>> command
'/bin/echo </verbosegc> >> /tmp/jruby.log'
>>process = subprocess.Popen(command.split(),  stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)
>>> output= process.communicate()[0]
>>> output
'</verbosegc> >> /tmp/jruby.log\n

我还打印出 process.pid,然后使用 ps -ef | 检查 pid grep pid。结果表明进程pid已经完成。

【问题讨论】:

  • 以这种方式使用split() 是一种代码味道。不要这样做。

标签: python bash shell subprocess popen


【解决方案1】:

如果您想将输出附加到文件中,只需使用传递文件对象,除非您设置shell=True,否则您无法重定向到文件:

command = ['/bin/echo', '</verbosegc>']

with open('/tmp/jruby.log',"a") as f:
     subprocess.check_call(command, stdout=f,stderr=subprocess.STDOUT)

【讨论】:

  • @CharlesDuffy,这就是我在回答中所做的,我的意思是如果不使用 shell=True 就无法使用&gt;&gt;
  • 非常正确,并且经过编辑,评论不再具有误导性; +1。
  • @shijiexu,我使用了 check_call,因为当你想将输出重定向到文件时,我看不到使用 Popen 的逻辑。
【解决方案2】:

subprocess.Popen 的第一个参数是数组['/bin/echo', '&lt;/verbosegc&gt;', '&gt;&gt;', '/tmp/jruby.log']。当subprocess.Popen 的第一个参数是数组时,它不会启动shell 来运行命令,而shell 负责将&gt;&gt; /tmp/jruby.log 解释为“将输出写入jruby.log”。

为了使&gt;&gt; 重定向在此命令中起作用,您需要将command 直接传递给subprocess.Popen(),而不将其拆分为列表。您还需要引用第一个参数(否则 shell 将以您不希望的方式解释“”字符):

command = '/bin/echo "</verbosegc>" >> /tmp/jruby.log'
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True)

【讨论】:

  • 执行 Popen 时仍然失败。 >>> process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) Traceback(最近一次调用最后):文件“”,第 1 行,在 文件中“/homes/sxu3/tools/python_install/lib/python2.7/subprocess.py”,第 710 行,在 init errread, errwrite) 文件“/homes/sxu3/tools/python_install/lib/ python2.7/subprocess.py",第 1335 行,在 _execute_child raise child_exception OSError: [Errno 2] No such file or directory
  • 你是对的:你需要添加shell=True 参数以使Popen 调用一个shell。我粗心。所以:subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, shell=True)
  • 数组在有和没有shell=True 的情况下都可以使用,尽管它们的语义在不同的情况下差别很大——请参阅我的答案以获取前者的示例。 :)
【解决方案3】:

考虑以下几点:

command = [ 'printf "%s\n" "$1" >>"$2"',  # shell script to execute
            '',                           # $0 in shell
            '</verbosegc>',               # $1
            '/tmp/jruby.log' ]            # $2
subprocess.Popen(command, shell=True)

第一个参数是引用$1$2 的shell 脚本,它们依次作为单独的参数传递。将数据与代码分开,而不是试图将前者替换为后者,这是防止 shell 注入的一种预防措施(将其视为类似于 SQL 注入)。


当然,实际上不要在 Python 中做这样的事情——文件 IO 的原生原语更合适。

【讨论】:

    【解决方案4】:

    您是否尝试过不拆分命令and using shell=True?我通常的格式是:

     process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
     output = process.stdout.read()       # or .readlines()
    

    【讨论】:

      猜你喜欢
      • 2011-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多