3

Using the subprocess module how do I get the following command to work?

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';" 

This command works perfectly when I run it in a bash shell but I can't get it to work when running from within Python. I'm trying to do this from within Python because I need to be able to modify the query and get different result sets back and then process them in Python. I can't use one of the nice Python database connectors for various reasons which leaves me trying to pipe output from isql.

My code currently looks similar to the following:

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() 

However I have tried lots of variations:

  • Using the entire command as a string, or as a list of strings.
  • Using check_output vs Popen.
  • Using communicate() to try and send the query to the isql command or having the query be part of the command string using a heredoc.
  • Using shell = True or not.
  • Specifying /bin/bash or using the default /bin/sh.
  • Lots of different quoting and escaping patterns.

And pretty much every permutation of the above.

In no case do I receive the output of the query that I'm looking for. I'm pretty sure that the command isn't being sent to the shell as is but I can't tell what is being sent to the shell.

I feel like this should be pretty simple, send a command to the shell and get the output back, but I just can't make it work. I can't even see what command is being sent to the shell, even using pdb.

4
  • Have you tested your subprocess on simple commands, like ls, whoami, etc? Commented Sep 10, 2015 at 20:10
  • is it comma intentional after -d? Commented Sep 10, 2015 at 20:54
  • @J.F.Sebastian Yes. Its the delimiter. Commented Sep 10, 2015 at 21:02
  • Okay. I now have working code. I think it was some combination of using shlex, which I hadn't been before, specifying 'input=' before my query string in the communicate() function and using a raw string with a single backslash as opposed to a plain string with a double backslash. Thank you all for your help. Commented Sep 10, 2015 at 21:10

2 Answers 2

2

shell=True makes subprocess use /bin/sh by default. <<< "here-string" is a bash-ism; pass 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 

You should also use raw-string literals to avoid escaping backslashes: "\\u0061" == r"\u0061" != u"\u0061":

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

Though you don't need shell=True here. You could pass the input as a string using process.communicate(input=input_string):

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

The result could look like:

#!/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';") 
Sign up to request clarification or add additional context in comments.

Comments

2

Try giving this a shot:

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 

The idea here is to separate the here-string redirection from the isql command execution. This example will pipe the here-string into the stdin of process via process.communicate(). I'm also using shlex.split() to tokenize the command and its arguments.

Edit: Removed Shell=True after reviewing comment from J.F. Sebastian

3 Comments

use subprocess.check_output
@amirouche You may be correct but I could never get check_ouput to function as expected.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.