How to use python -c "code here" with newlines? - python

The command
python -c "print('hello')"
runs the code inside the quotes successfully, both in Linux (bash) and Windows (cmd.exe).
But how to pass code with newlines, with python -c?
Example: both
python -c "for i in range(10): if i % 2 == 0: print('hello')"
python -c "for i in range(10):\n if i % 2 == 0:\n print('hello')"
fail.
Example use case: I need to send a SSH command (with paramiko) to execute a short Python code on a remote server, so I need to pass one command like
ssh.exec_command('python -c "..."').

You can use bash's $'foo' string syntax to get newlines:
python -c $'for i in range(10):\n if i % 2 == 0:\n print("hello")'
(I'm using single space indents here)
For windows, you really should be using powershell, which has `n as a newline:
python -c "for i in range(10):`n if i % 2 == 0:`n print('hello')"
In cmd.exe, it seems that you can use ^ to escape a newline, however I'm unable to test this currently so you should refer to this question's answers.

You can use a bash "heredoc" (also available ksh, and POSIX shells):
python <<EOF
import numpy as np
print(dir(np))
EOF

While not using -c it is worth mentioning that, if using Bash, you can pipe echoed code directly to python.
echo -e 'for i in range(10):\n if i % 2 == 0:\n print("hello")' | python
Following Aplet123's lead and using using single space indents.

One way could be with exec(), what make strings executable. It looks bad, but it works.
python -c "exec(\"for i in range(10):\n if i % 2 == 0:\n print('hello')\")"

Related

How should I embed a python script in a Makefile?

I want to embed a python script in a Makefile
I built a python -c script (below), and it works well in my MacBook Hyper terminal:
% python -c $'from subprocess import getstatusoutput\noutput=getstatusoutput("open --background -a Docker")\nif int(output[0])>0:\n print("Docker desktop failed to launch: exit-code:{}".format(output[0]))'
For reasons I can't yet figure out, this seems to fail if I build a Makefile with it (note: a tab is four spaces... I used tab indentation in the Makefile).
all:
$(shell python -c $'from subprocess import getstatusoutput\noutput=getstatusoutput("open --background -a Docker")\nif int(output[0])>0:\n print("Docker desktop failed to launch: exit-code:{}".format(output[0]))')
Running the make all target...
% make all
/bin/sh: -c: line 0: syntax error near unexpected token `('
/bin/sh: -c: line 0: `python -c from subprocess import getstatusoutput\noutput=getstatusoutput("open --background -a Docker")\nif int(output[0])>0:\n print("Docker desktop failed to launch: exit-code:{}".format(output[0]))''
make: `all' is up to date.
%
I have been struggling with this for a while...
Can someone help explain why make all fails and the best way to fix this python -c command? My shell CLI python -c ... command successfully launches Docker desktop on my MacBook.
I understand there are non-python ways to solve this specific problem... I need a general python Makefile solution.
Using python -c in a Makefile is tricky because of Python's indentation requirements. One simple solution is to use SHELL=/bin/bash if you want to use a Bash "C-style" string:
SHELL=/bin/bash
all:
# python command must be wrapped in single quotes _and_ have double dollar sign in front
python -c $$'from subprocess import getstatusoutput\noutput=getstatusoutput("open --background -a Docker")\nif int(output[0])>0:\n print("Docker desktop failed to launch: exit-code:{}".format(output[0]))'
(Notice how the dollar sign needs to be doubled to escape it. And obviously, this restricts the portability of your Makefile to systems where Bash is available. The $'...' syntax lets you use escape codes like \n and \t within a string, and have them expanded to newline and tab, respectively. This construct specifically requires a leading dollar sign and single quotes around the string - merely '...' does someting slightly different, and $"..." does something entirely different.)
You could also define a make multi-line variable. But in this isolated case, Python is not playing any useful role anyway.
all:
open --background -a Docker
make will terminate with an error message if open fails; printing essentinally the same message from Python seems superfluous. If you want to proceed in spite of the error, you can do
all:
open --background -a Docker || \
echo "Docker desktop failed to launch: exit-code: $$?"
... though I assume failing to fail (sic) from the Python script was just a mistake.
I found a fairly simple way to embed a multiline python script in a Makefile...
Save this as Makefile...
define MULTILINE_PYTHON_SCRIPT
###########################################
# Start multiline python string here...
###########################################
from subprocess import getstatusoutput as gso
print("Here we go:")
for hello_int in [1, 2, 3,]:
print(' Hello World %i' % hello_int)
retval, _ = gso("ls -la")
assert retval==0, "ls command execution failed"
###########################################
# End of multiline python string...
###########################################
endef
export MULTILINE_PYTHON_SCRIPT
EMBEDDED_PY := python -c "$$MULTILINE_PYTHON_SCRIPT"
.PHONY: nothing
nothing:
echo "raw makefile command"
.PHONY: test
test:
$(EMBEDDED_PY)
.PHONY: all
all:
open --background -a Docker
Testing the output:
% make nothing
echo "raw makefile command"
raw makefile command
%
% make test
python -c "$MULTILINE_PYTHON_SCRIPT"
Here we go:
Hello World 1
Hello World 2
Hello World 3
%
%

Printing .py file output in command line

I am trying to access a python function from the command line, and I would like to write such a command that will print the output in the terminal. The below doesn't work. What could I change?
python -c 'from laser import Laser; laser = Laser();l = laser.embed_sentences("hello", lang = "en").shape == (1, 1024); print(l)'
(base) ~ % python -c 'print("hello, world")'
hello, world
Printing works fine for me when running python through python -c. Are you sure your terminal isn't truncating your output by omitting the last (and in this case, only) line? You could try creating a single line file (no newline at the end) and then running cat [filename] (which is how I sometimes discover that my terminal is doing this)
-c cmd : program passed in as string (terminates option list)
That is the correct flag to be used. This must be a CLI config issue. Or the script is taking longer than you are expecting to run and it appears no output is generated.
Does python -c 'print("hello")' work?

How to write an inline if statement with python executed with -c in a Makefile?

I am trying to write this small python program to execute with python through the -c option:
python -c "import sys;if 2==sys.version_info.major: raise RuntimeError('Must use python3')"
However, this is raising a syntax error:
File "<string>", line 1
import sys;if 2==sys.version_info.major: raise RunTimeError('Must use python3')
^
SyntaxError: invalid syntax
is there a way to write this such that it does work in the above? And if it's invalid, is there a canonical reference to what syntaxes are allowed in -c executed code?
I am doing this in a Makefile.
Literal newlines are perfectly valid inside single-quoted strings in POSIX shells:
python -c '
import sys
if 2 == sys.version_info.major:
raise RuntimeError("Must use python3")
'
This means you aren't dependent on having bash, ksh93 or zsh with the $'' extension.
If this is in a Makefile:
define python_script
import sys
if 2 == sys.version_info.major:
raise RuntimeError("Must use python3")
endef
test:
python -c "$$python_script"
You can use \n.
python -c "import sys"$'\n'"if 2 == sys.version_info.major:"$'\n'" raise RuntimeError('Must use python3')"
...this assumes you're using bash or some closely related shell. But otherwise obviously you can still just have newlines in the string, especially if you're calling python -c from a program using exec or something.

python execution directly via command line linux

how can i run an easy python script and save it in a file but directly in linux command line:
fox#fox:/opt/gera# python -c print "aaaaa" > myfileName
but it is just print nothing instead of "aaaaa".
You have to quote the whole command:
python -c 'print "aaaaa"' > myfileName
Otherwise you execute print in Python (which, in Python 2 prints a linebreak and in Python 3 does nothing since you'd just evaluate the function print without calling it) and pass aaaaa as an argument to the script.
You need to put quotes around the code.
python -c 'print "aaaaa"' > myfileName
python -c 'print "aaaaa"' > myfileName
in your example python is running python -c print and giving "aaaaa" as an argument.
man python:
-c command
Specify the command to execute. This terminates the option list (following options are passed as arguments to the command).
passed as arguments to the command -- means everything after the command is available as sys.argv:
$ python -c 'import sys; print sys.argv' -a -b -c -d
['-c', '-a', '-b', '-c', '-d']
To make a single argument (command in terms of the man excerpt above) out of a list of arguments you just take these in quotes:
$ python -c 'print "aaaaa"'
aaaaa

Python file testing line in BASH program failing with syntax error

Hey guys I'm trying to integrate some PY into my shell script and running across
the following error, I though quote should have quoted my variable but it looks
like it's not doing what I expected, can someone help me troubleshoot this?
#!/bin/bash
host='user#localhost'
path='/home/user/file'
python -c "return subprocess.call(['ssh', '$host', 'test -e ' + pipes.quote($path)]) == 0"
File "<string>", line 1
return subprocess.call(['ssh', "user#localhost", 'test -e ' + pipes.quote(/home/jdaniel/sent)]) == 0
^
SyntaxError: invalid syntax
python -c "return subprocess.call(['ssh', '$host', 'test -e ' + pipes.quote(\"$path\")]) == 0"
I would assume
as an aside .. why are you not just calling ssh from the bash? what benefit are you getting by using python here in this fashion? and do you not need to use import subprocess when you use the -c flag?
I would choose to do this whole program either in python or bash ... but mixing them like this feels slightly silly (especially given what your python code does)
You'll need to change this
pipes.quote($path)
to
pipes.quote('$path')
as pipes.quote() is expecting a string
I'd say Its better to use shell instead of python
#!/bin/bash
host='user#localhost'
path='/home/user/file'
ssh -q $host "test -e $path"

Categories