Any idea how this can be fixed?
Your problem is created by the fact that Python statements, separated by ;
, are only allowed to be "small statements", which are all one-liners. From the grammar file in the Python docs:
stmt: simple_stmt | compound_stmt simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE small_stmt: (expr_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | nonlocal_stmt | assert_stmt)
Compound statements can't be included on the same line with other statements via semicolons - so doing this with the -c
flag becomes very inconvenient.
When demonstrating Python while in a bash shell environment, I find it very useful to include compound statements. The only simple way of doing this reliably is with heredocs (a posix shell thing).
Use a heredoc (created with <<
) and Python's command line interface option, -
:
$ python - <<-"EOF"
import sys # 1 tab indent
for r in range(10): # 1 tab indent
print('rob') # 1 tab indent and 4 spaces
EOF
Adding the -
after <<
(the <<-
) allows you to use tabs to indent (Stackoverflow converts tabs to spaces, so I've indented 8 spaces to emphasize this). The leading tabs will be stripped.
You can do it without the tabs with just <<
:
$ python - << "EOF"
import sys
for r in range(10):
print('rob')
EOF
Putting quotes around EOF
prevents parameter and arithmetic expansion. This makes the heredoc more robust.
If you use double-quotes, you'll get shell-expansion:
$ python -c "
> import sys
> for p in '$PATH'.split(':'):
> print(p)
> "
/usr/sbin
/usr/bin
/sbin
/bin
...
To avoid shell expansion use single-quotes:
$ python -c '
> import sys
> for p in "$PATH".split(":"):
> print(p)
> '
$PATH
Note that we need to swap the quote characters on the literals in Python - we basically can't use quote character being interpreted by BASH. We can alternate them though, like we can in Python - but this already looks quite confusing, which is why I don't recommend this:
$ python -c '
import sys
for p in "'"$PATH"'".split(":"):
print(p)
'
/usr/sbin
/usr/bin
/sbin
/bin
...
This is not very readable:
echo -e "import sys\nfor r in range(10): print 'rob'" | python
Not very readable, and additionally difficult to debug in the case of an error:
python -c "exec(\"import sys\\nfor r in range(10): print 'rob'\")"
Perhaps a bit more readable, but still quite ugly:
(echo "import sys" ; echo "for r in range(10): print 'rob'") | python
You'll have a bad time if you have "
's in your python:
$ python -c "import sys > for r in range(10): print 'rob'"
Don't abuse map
or list comprehensions to get for-loops:
python -c "import sys; map(lambda x: sys.stdout.write('rob%d\n' % x), range(10))"
These are all sad and bad. Don't do them.