8

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?

daniel
  • 2,568
  • 24
  • 32

4 Answers4

9

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)

'
asmeurer
  • 86,894
  • 26
  • 169
  • 240
4

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.

jmunsch
  • 22,771
  • 11
  • 93
  • 114
3

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!

CDspace
  • 2,639
  • 18
  • 30
  • 36
3

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

Jason S
  • 13,538
  • 2
  • 37
  • 42