- To make this answer work with Python 3.x as well, print
is called as a function: in 3.x, only print('foo')
works, whereas 2.x also accepts print 'foo'
.
- For a cross-platform perspective that includes Windows, see kxr's helpful answer.
In bash
, ksh
, or zsh
:
Use an ANSI C-quoted string ($'...'
), which allows using \n
to represent newlines that are expanded to actual newlines before the string is passed to python
:
python -c $'import sys\nfor r in range(10): print("rob")'
Note the \n
between the import
and for
statements to effect a line break.
To pass shell-variable values to such a command, it is safest to use arguments and access them via sys.argv
inside the Python script:
name='rob' # value to pass to the Python script
python -c $'import sys\nfor r in range(10): print(sys.argv[1])' "$name"
See below for a discussion of the pros and cons of using an (escape sequence-preprocessed) double-quoted command string with embedded shell-variable references.
To work safely with $'...'
strings:
\
instances in your original source code.
\<char>
sequences - such as \n
in this case, but also the usual suspects such as \t
, \r
, \b
- are expanded by $'...'
(see man printf
for the supported escapes)'
instances as \'
.If you must remain POSIX-compliant:
Use printf
with a command substitution:
python -c "$(printf %b 'import sys\nfor r in range(10): print("rob")')"
To work safely with this type of string:
\
instances in your original source code.
\<char>
sequences - such as \n
in this case, but also the usual suspects such as \t
, \r
, \b
- are expanded by printf
(see man printf
for the supported escape sequences).Pass a single-quoted string to printf %b
and escape embedded single quotes as '\''
(sic).
Using single quotes protects the string's contents from interpretation by the shell.
That said, for short Python scripts (as in this case) you can use a double-quoted string to incorporate shell variable values into your scripts - as long as you're aware of the associated pitfalls (see next point); e.g., the shell expands $HOME
to the current user's home dir. in the following command:
python -c "$(printf %b "import sys\nfor r in range(10): print('rob is $HOME')")"
However, the generally preferred approach is to pass values from the shell via arguments, and access them via sys.argv
in Python; the equivalent of the above command is:
python -c "$(printf %b 'import sys\nfor r in range(10): print("rob is " + sys.argv[1])')" "$HOME"
While using a double-quoted string is more convenient - it allows you to use embedded single quotes unescaped and embedded double quotes as \"
- it also makes the string subject to interpretation by the shell, which may or may not be the intent; $
and `
characters in your source code that are not meant for the shell may cause a syntax error or alter the string unexpectedly.
\
processing in double-quoted strings can get in the way; for instance, to get Python to produce literal output ro\b
, you must pass ro\\b
to it; with a '...'
shell string and doubled \
instances, we get:python -c "$(printf %b 'import sys\nprint("ro\\\\bs")')" # ok: 'ro\bs'
"..."
shell string:python -c "$(printf %b "import sys\nprint('ro\\\\bs')")" # !! INCORRECT: 'rs'
"\b"
and "\\b"
as literal \b
, requiring a dizzying number of additional \
instances to achieve the desired effect:python -c "$(printf %b "import sys\nprint('ro\\\\\\\\bs')")"
To pass the code via stdin
rather than -c
:
Note: I'm focusing on single-line solutions here; xorho's answer shows how to use a multi-line here-document - be sure to quote the delimiter, however; e.g., <<'EOF'
, unless you explicitly want the shell to expand the string up front (which comes with the caveats noted above).
In bash
, ksh
, or zsh
:
Combine an ANSI C-quoted string ($'...'
) with a here-string (<<<...
):
python - <<<$'import sys\nfor r in range(10): print("rob")'
-
tells python
explicitly to read from stdin (which it does by default).
-
is optional in this case, but if you also want to pass arguments to the scripts, you do need it to disambiguate the argument from a script filename:
python - 'rob' <<<$'import sys\nfor r in range(10): print(sys.argv[1])'
If you must remain POSIX-compliant:
Use printf
as above, but with a pipeline so as to pass its output via stdin:
printf %b 'import sys\nfor r in range(10): print("rob")' | python
With an argument:
printf %b 'import sys\nfor r in range(10): print(sys.argv[1])' | python - 'rob'