【问题标题】:Using subprocess to get output使用子进程获取输出
【发布时间】:2015-12-07 05:56:14
【问题描述】:

使用 subprocess 模块如何使以下命令起作用?

isql -v -b -d, DSN_NAME "DOMAIN\username" password <<< 
"SELECT column_name, data_type 
 FROM database_name.information_schema.columns 
 WHERE table_name = 'some_table';"

当我在 bash shell 中运行此命令时,它可以完美运行,但在 Python 中运行时,我无法让它运行。我正在尝试从 Python 中执行此操作,因为我需要能够修改查询并获取不同的结果集,然后在 Python 中处理它们。由于各种原因,我无法使用其中一个不错的 Python 数据库连接器,这让我试图从 isql 管道输出。

我的代码目前类似于以下内容:

bash_command = '''
               isql -v -b -d, DSN_NAME "DOMAIN\username" password <<< 
               "SELECT column_name, data_type 
                FROM database_name.information_schema.columns 
                WHERE table_name = 'some_table';" 
               '''
process = subprocess.Popen(bash_command,
                           shell=True,
                           stdout=subprocess.PIPE,
                           stderr=subprocess.PIPE)
output, error = process.communicate()

但是我尝试了很多变化:

  • 将整个命令用作字符串或字符串列表。
  • 使用 check_output 与 Popen。
  • 使用communicate() 尝试将查询发送到isql 命令或使用heredoc 使查询成为命令字符串的一部分。
  • 使用 shell = True 与否。
  • 指定 /bin/bash 或使用默认的 /bin/sh。
  • 许多不同的引用和转义模式。

几乎所有上述的排列。

在任何情况下,我都不会收到我正在寻找的查询的输出。我很确定命令没有按原样发送到 shell,但我不知道发送到 shell 的是什么。

我觉得这应该很简单,向 shell 发送一个命令并返回输出,但我就是无法让它工作。即使使用 pdb,我什至看不到正在向 shell 发送什么命令。

【问题讨论】:

  • 您是否使用简单的命令(如 ls、whoami 等)测试过您的子进程?
  • -d后面加逗号是不是故意的?
  • @J.F.Sebastian 是的。它是分隔符。
  • 好的。我现在有工作代码。我认为这是使用 shlex 的某种组合,我以前没有使用过,在通信()函数中的查询字符串之前指定“input=”,并使用带有单个反斜杠的原始字符串,而不是带有双反斜杠。谢谢大家的帮助。

标签: python subprocess


【解决方案1】:

shell=True 使subprocess 默认使用/bin/sh&lt;&lt;&lt; "here-string" 是一种 bash 主义;通过executable='/bin/bash':

>>> import subprocess
>>> subprocess.call(u'cat <<< "\u0061"', shell=True)
/bin/sh: 1: Syntax error: redirection unexpected
2
>>> subprocess.call(u'cat <<< "\u0061"', shell=True, executable='/bin/bash')
a
0

您还应该使用原始字符串文字以避免转义反斜杠:"\\u0061" == r"\u0061" != u"\u0061":

>>> subprocess.call(r'cat <<< "\u0061"', shell=True, executable='/bin/bash')
\u0061
0

虽然你在这里不需要shell=True。您可以使用 process.communicate(input=input_string) 将输入作为字符串传递:

>>> process = subprocess.Popen(['cat'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
>>> process.communicate(br"\u0061")
('\\u0061', None)

结果可能如下所示:

#!/usr/bin/env python
import shlex
from subprocess import Popen, PIPE

cmd = shlex.split(r'isql -v -b -d, DSN_NAME "DOMAIN\username" password')
process = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
output, errors = process.communicate(
    b"SELECT column_name, data_type "
    b"FROM database_name.information_schema.columns "
    b"WHERE table_name = 'some_table';")

【讨论】:

    【解决方案2】:

    尝试一下:

    import shlex
    from subprocess import Popen, PIPE, STDOUT
    
    sql_statement = '''"SELECT column_name, data_type 
    FROM database_name.information_schema.columns 
    WHERE table_name = 'some_table';"'''
    
    isqlcommand = 'isql -v -b -d, DSN_NAME "DOMAIN\username" password'
    isqlcommand_args = shlex.split(isqlcommand)
    process = Popen(isqlcommand_args, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
    output = process.communicate(input=sql_statement)[0]
    print output
    

    这里的想法是将here-string重定向与isql命令执行分开。此示例将通过process.communicate() 将here-string 通过管道传输到process 的标准输入中。我还使用shlex.split() 来标记命令及其参数。

    编辑在查看 J.F. Sebastian 的评论后删除了 Shell=True

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-22
    • 2019-01-25
    • 2011-09-08
    • 2020-03-03
    相关资源
    最近更新 更多