58

I want to run a mysql command and set the output of that to be a variable in my python script.

Here is the shell command I'm trying to run:

$ mysql my_database --html -e "select * from limbs" | ./script.py

Here is the python script:

#!/usr/bin/env python

import sys

def hello(variable):
    print variable

How would I accept the variable in the python script and have it print the output?

0

7 Answers 7

68

You need to read from stdin to retrieve the data in the python script e.g.

#!/usr/bin/env python

import sys

def hello(variable):
    print variable

data = sys.stdin.read()
hello(data)

If all you want to do here is grab some data from a mysql database and then manipulate it with Python I would skip piping it into the script and just use the Python MySql module to do the SQL query.

Sign up to request clarification or add additional context in comments.

2 Comments

It looks like the shebang is important, which is why none of the other examples worked. Without it, it will just hang forever instead.
@Antimony Without the shebang, you just have to call the Python executable yourself: echo 'foo' | python script.py
38

If you want your script to behave like many unix command line tools and accept a pipe or a filename as first argument, you can use the following:

#!/usr/bin/env python
import sys

# use stdin if it's full                                                        
if not sys.stdin.isatty():
    input_stream = sys.stdin

# otherwise, read the given filename                                            
else:
    try:
        input_filename = sys.argv[1]
    except IndexError:
        message = 'need filename as first argument if stdin is not full'
        raise IndexError(message)
    else:
        input_stream = open(input_filename, 'rU')

for line in input_stream:
    print(line) # do something useful with each line

Comments

17

When you pipe the output of one command to a pytho script, it goes to sys.stdin. You can read from sys.stdin just like a file. Example:

import sys

print sys.stdin.read()

This program literally outputs its input.

1 Comment

+1 for mentioning "just like a file", which will hopefully lead the OP to realize he can also do things like "for line in sys.stdin:", etc.
11

Since this answer pops up on Google at the top when searching for piping data to a python script, I'd like to add another method, which I have found in [J. Beazley's Python Cookbook][1] after searching for a less 'gritty' aproach than using sys. IMO, more pythonic and self-explanatory even to new users.

import fileinput
with fileinput.input() as f_input:
    for line in f_input:
        print(line, end='')

This approach also works for commands structured like this:

$ ls | ./filein.py          # Prints a directory listing to stdout.
$ ./filein.py /etc/passwd   # Reads /etc/passwd to stdout.
$ ./filein.py < /etc/passwd # Reads /etc/passwd to stdout.

If you require more complex solutions, you can compine argparse and fileinput [as shown in this gist by martinth][2]:

import argparse
import fileinput

if __name__ == '__main__':
    parser = ArgumentParser()
    parser.add_argument('--dummy', help='dummy argument')
    parser.add_argument('files', metavar='FILE', nargs='*', help='files to read, if empty, stdin is used')
    args = parser.parse_args()

    # If you would call fileinput.input() without files it would try to process all arguments.
    # We pass '-' as only file when argparse got no files which will cause fileinput to read from stdin
    for line in fileinput.input(files=args.files if len(args.files) > 0 else ('-', )):
        print(line)


  [1]: https://library.oreilly.com/book/0636920027072/python-cookbook-3rd-edition/199.xhtml?ref=toc#_accepting_script_input_via_redirection_pipes_or_input_files
  [2]: https://gist.github.com/martinth/ed991fb8cdcac3dfadf7

6 Comments

Getting an error with this method (using python 2.7) Traceback (most recent call last): File "./pipetome.py", line 4, in <module> with fileinput.input() as f_input: AttributeError: FileInput instance has no attribute 'exit'
The above was only tested in Python3 - perhaps instead of with try f_input = fileinput.input() ?
but how to differentiate args and stdin, e.g send_mail -to [email protected] -subject 'passwd' < /etc/passwd
I've updated the answer with an example solving your stated problem.
FYI: Line 1 should be import argparse not argpase ;-)
|
10

You can use the command line tool xargs

echo 'arg1' | xargs python script.py

arg1 is now accessible from sys.argv[1] in script.py

4 Comments

This does not appear to be working with multi-line pipe contents.
@ZephaniahGrunschlag I think that is the same as giving an additional CLI argument, like: python script.py "gday". A one-liner without xargs dependence would be nice.
I think my answer was out of context, so I deleted it
Drawbacks to the xargs approach is discussed in How to pipe input to python...
7

The one-liner that also works for Windows and on Python 3.10.3 is using sys.stdin.read(), like this:

echo 'Hello!' | python -c "import sys;d=sys.stdin.read(); print('{}\n'.format(d))"

1 Comment

This also works in MacOS and Linux, and is the form I was looking for... thank you.
0

I stumbled on this trying to pipe a bash command to a python script that I did not write (and didn't want to modify to accept sys.stdin). I found process substitution mentioned here (https://superuser.com/questions/461946/can-i-use-pipe-output-as-a-shell-script-argument) to work fine.

Ex. some_script.py -arg1 <(bash command)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.