Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using an import and a for loop when passing a program as a string to Python

Tags:

python

A colleague recently sent me a bash script that included some inline Python. The command he used was of the form:

$ echo -e 'from foo import bar\nfor i in range(10):\n   bar(i+1).thing = "something"\n\n' | python

The command worked just fine, but I asked why he didn't use python -c. On further investigation, we were unable to translate this to a form that python -c would accept as it appears that Python disallows statements prior to a for loop even when delimited by a semicolon.

The first example below shows that you can import, and print out the imported object. The second example shows that you can use a for loop and print from the for loop. The third example combines the first two, and results in a SyntaxError. And finally, the forth example shows the SyntaxError results when using an expression prior to the for loop:

$ python -c "from sys import argv; print argv"
['-c']
$ python -c "for v in [1,2,3,4]: print v"
1
2
3
4
$ python -c "from sys import argv; for v in argv: print v"
  File "<string>", line 1
    from sys import argv; for v in argv: print v
                            ^
SyntaxError: invalid syntax
$ python -c "x = 5; for i in [1,2,3]: print i"
  File "<string>", line 1
    x = 5; for i in [1,2,3]: print i
         ^
SyntaxError: invalid syntax

In hindsight, the SyntaxError is not that surprising given that the code is not valid when saved in a script, and that the grammar for statements combined with whitespace restrictions can impose this type of limitation. That being said, is there a way to allow a statement prior to a compound statement through python -c?

like image 865
daniel Avatar asked Aug 08 '14 20:08

daniel


4 Answers

To clarify CDspace's answer, note that in Bash, unlike Python, newlines do not terminate string literals. So you can do the following:

$python -c 'import sys
for i in range(10):
  print(i)

'
like image 153
asmeurer Avatar answered Oct 06 '22 15:10

asmeurer


Another option:

python -c "exec(\"x = 5\nfor i in [1,2,3]:\n\tprint(i)\")"

Edit:

Tested and Works for both windows CMD, and Bash.

like image 39
jmunsch Avatar answered Oct 06 '22 16:10

jmunsch


From the docs (emphasis added), try it with newlines instead of semi-colons.

When called with -c command, it executes the Python statement(s) given as command. Here command may contain multiple statements separated by newlines. Leading whitespace is significant in Python statements!

like image 35
CDspace Avatar answered Oct 06 '22 14:10

CDspace


You already have an answer regarding -c but for your use case, a here document has the advantage of not having string quoting issues as does a -c parameter wrapped in '' or "", because you can use any unique delimiter that you want that will not appear in your script anywhere.

python <<'PYSCRIPT'
for i in range(10):
    print(i)
PYSCRIPT

(Single quotes around the initial delimiter if you don't want expansion of shell variables, no quotes if you do.)

like image 20
Jason S Avatar answered Oct 06 '22 15:10

Jason S