使用子进程获取输出

Using subprocess to get output

使用 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 中时,此命令完美运行,但当 运行 在 [=43] 中运行时,我无法使其运行=].我正在尝试从 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()

但是我尝试了很多变体:

以及上面的几乎所有排列。

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

的是什么

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

尝试一下:

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 的评论后删除了 Shell=True。塞巴斯蒂安

shell=True 使 subprocess 默认使用 /bin/sh<<< "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';")