I want to call an R program from a python script.
I wrote the following:
os.system("cat " + variableName + " | code.R")
It returns the error: sh: 1 : code.R: not found
cat: write error: Broken pipe
Yet, I am sure of the name of the R file.
Why is it not working?
So, if code.R is a script that has to be interpreted you must build the pipe to the interpreter not to the script. You receive a Broken PIPE error because code.R by it self don't know how to handle command line arguments.
On the other hand if what you want is store the variable value inside code.R you have to change | by >>.
os.system("cat " + variablename + ">> code.R")
EDIT: Since it's working from terminal, try this:
import subprocess
input = open(variableName, "r")
result = suprocess.call(["code.R"], stdin=input) # result is the return code for the command being called.
see subprocess.call for more details.
Is code.R in the current working directory? Is it executable? Can you run cat xxx | code.R from the shell and have it work properly, instead of running your python program?
Related
I have a lua script configured to trigger once a subject's metadata is sent to a specific online Orthanc server. I want it to scrape the subject ID and then call a python script with the ID as an argument. When I put the command manually into my terminal, it works, but the lua script doesn't seem to be executing it.
There is a built-in Orthanc function that scrapes the ID from the subject once it is sent to the server.
The initial lua script had the following:
path = "/path/to/python_script.py"
os.execute("python " .. path .. " " .. subjectId)
But the script wasn't getting called.
I first wanted to see if it was even getting triggered, so I added in:
file = io.open("/path/to/textfile.txt", "a")
file:write("\nI am alive, subjectId is " .. subjectId)
file:close()
And that worked!
So then I wanted to see if there was something wrong with os.execute, so I did:
os.execute("touch /same/path/deleteme.txt")
which worked as well.
So it doesn't seem like os.execute isn't working.
Does anyone have any idea why the script isn't getting called?
EDIT: Does anyone know how to check the status of the os.execute command?
EDIT: I am using Python 3.5.6, Lua 5.1.4, and Linux.
Firstly, to address you question about checking the status from os.execute: this function returns a a status code, which is system dependent (https://www.lua.org/manual/5.1/manual.html#pdf-os.execute). I tried to handle an invalid command by recording this status code, but found it to be somewhat unhelpful; additionally, the shell itself printed an error message.
os.execute("hello") -- 'hello' is not a shell command.
> sh: 1: hello: not found
This error message from the shell was not being caught and read by my Lua script, but was instead being sent directly to stderr. (Good reference about that: https://www.jstorimer.com/blogs/workingwithcode/7766119-when-to-use-stderr-instead-of-stdout.)
I found an interesting solution for catching any error output using temp files.
tmpname = os.tmpname()
os.execute(string.format("hello 2> %s", tmpname))
for line in io.lines(tmpname) do
print("line = " .. line)
end
This prints: line = sh: 1: hello: not found, which is the error described earlier. os.execute should also return the status of the command like this:
a, b, c = os.execute("echo hello")
> hello
print(a, b, c)
> true exit 0
d, e, f = os.execute("hello") -- An invalid command
> sh: 1: hello: not found
print(d, e, f)
> nil exit 127
In this example, c and f are the exit statuses of their respective commands. If the previous command, i.e. executing your Python script, failed, then the exit status should be non-zero.
To address your primary question regarding Python, I would double-check the path to the script--always a good idea to start with a simple sanity check. Consider using string.format to assemble the command like this:
command = string.format("python %s %i", tostring(path), tonumber(subjectId))
os.execute(command)
Also, it would be helpful to know which version of Lua/Python you are using, and perhaps your system as well.
EDIT: depending on whether or not you need them to remain for a bit, you should remove any temp files generated by os.tmpname with os.remove. I also attempted to replicate your situation with a simple test, and I had no trouble executing the Python script with os.execute in a Lua script located in a different directory.
For reference, this is the Lua script, called test.lua, I created in a temp directory called /tmp/throwaway:
#!/usr/bin/lua
local PATH_TO_PY_FILE = "/tmp/py/foo.py"
local function fprintf(fil, formal_arg, ...)
fil:write(string.format(formal_arg, ...))
return
end
local function printf(formal_arg, ...)
io.stdout:write(string.format(formal_arg, ...))
return
end
local function foo(...)
local t = {...}
local cmd = string.format("python3 %s %s", PATH_TO_PY_FILE, table.concat(t, " "))
local filename = os.tmpname()
local a, b, status = os.execute(string.format("%s 2> %s", cmd, filename))
printf("status = %i\n", status)
local num = 1
for line in io.lines(filename) do
printf("line %i = %s\n", num line)
num = num + 1
end
os.remove(filename)
return
end
local function main(argc, argv)
foo()
foo("hello", "there,", "friend")
return 0
end
main(#arg, arg)
(Please forgive my C-style main function, haha.)
In a separate temp directory, called /tmp/py, I created a Python file that looks like this:
import sys
def main():
for arg in sys.argv:
print(arg)
if __name__ == '__main__':
main()
The Lua script's function foo takes a variable number of arguments and supplies them as command-line arguments to the Python script; the Python script then simply prints those arguments one-by-one. Again, this was just a simple test for proof of concept.
The temp file created by os.tmpname should be in /tmp; as for your files, that is, your Lua and Python scripts, you would make sure you know exactly where those files are located. Hopefully that can resolve your problem.
Also, you could supply the path to the Python script--or any other necessary files--to the Lua script as command-line arguments and then slightly modify the existing code.
$> ./test.lua path-to-python-file
Then simply modify foo in test.lua to accept the Python file's path as an argument:
local function foo(py_path, ...)
local t = {...}
local cmd = string.format("python3 %s %s", py_path, table.concat(t, " "))
-- Everything else should remain the same.
end
My perl script is at path:
a/perl/perlScript.pl
my python script is at path:
a/python/pythonScript.py
pythonScript.py gets an argument from stdin, and returns result to stdout. From perlScript.pl , I want to run pythonScript.py with the argument hi to stdin, and save the results in some variable. That's what I tried:
my $ret = `../python/pythonScript.py < hi`;
but I got the following error:
The system cannot find the path specified.
Can you explain the path can't be found?
The qx operator (backticks) starts a shell (sh), in which prog < input syntax expects a file named input from which it will read lines and feed them to the program prog. But you want the python script to receive on its STDIN the string hi instead, not lines of a file named hi.
One way is to directly do that, my $ret = qx(echo "hi" | python_script).
But I'd suggest to consider using modules for this. Here is a simple example with IPC::Run3
use warnings;
use strict;
use feature 'say';
use IPC::Run3;
my #cmd = ('program', 'arg1', 'arg2');
my $in = "hi";
run3 \#cmd, \$in, \my $out;
say "script's stdout: $out";
The program is the path to your script if it is executable, or perhaps python script.py. This will be run by system so the output is obtained once that completes, what is consistent with the attempt in the question. See documentation for module's operation.
This module is intended to be simple while "satisfy 99% of the need for using system, qx, and open3 [...]. For far more power and control see IPC::Run.
You're getting this error because you're using shell redirection instead of just passing an argument
../python/pythonScript.py < hi
tells your shell to read input from a file called hi in the current directory, rather than using it as an argument. What you mean to do is
my $ret = `../python/pythonScript.py hi`;
Which correctly executes your python script with the hi argument, and returns the result to the variable $ret.
The Some of the other answers assume that hi must be passed as a command line parameter to the Python script but the asker says it comes from stdin.
Thus:
my $ret = `echo "hi" | ../python/pythonScript.py`;
To launch your external script you can do
system "python ../python/pythonScript.py hi";
and then in your python script
import sys
def yourFct(a, b):
...
if __name__== "__main__":
yourFct(sys.argv[1])
you can have more informations on the python part here
I am using Python subprocess module but the results are unexpected. I have successfully determined the correct command line strings (using another language) but cannot get a Python equivalent to work.
So I wrote some code in VBA which uses a Windows COM type library to spawn process and capture stdout, stderr. Using this I managed to write my program which generates elliptic curve keys and sign a file etc. An example command line which would run fine would be this
C:\Progra~1\OpenSSL-Win64\bin\openssl.exe ecparam -genkey -name secp384r1 -out n:\ECDSA\2017-11-30T203401\ec_key.pem
I am trying to convert the code to Python so that it runs on a linux box. I am using the same strategy in that I am spawning shells (because i have figured out all the right arguments in the VBA equivalent). I am not using a Python API like pyOpenSSL.
So I am using the subprocess module. I have never used this and am having trouble, initially I couldn't get the thing to work at all. I have managed to get something working but it looks like instead of executing the whole statement and generating a file (in the case given) it is instead dropping me into the OpenSSL prompt. That is to say it is not processing the arguments correctly. Here is my Python code
import os
import subprocess
import sys
class Expando(object):
pass
def RunShellAndWait(sExe, aArgs):
print(sExe + ' ' + ' '.join(aArgs))
# https://stackoverflow.com/questions/4760215/running-shell-command-from-python-and-capturing-the-output#answer-4760517
if (sys.platform[:3]=='win'):
suinfo = subprocess.STARTUPINFO()
suinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
SW_SHOWMAXIMIZED = 3
suinfo.wShowWindow = SW_SHOWMAXIMIZED
try:
result = subprocess.run(args=aArgs,executable=sExe,stdin=subprocess.PIPE,stdout=subprocess.PIPE, stderr=subprocess.PIPE,startupinfo=suinfo)
except:
print( "something went wrong with subprocess.run \r\nexec " + sExe + ' ' + ' '.join(aArgs))
else:
suinfo = None
retVal=Expando()
retVal.returnCode = result.returncode
retVal.sStdOut = result.stdout.decode('utf-8')
retVal.sStdErr = result.stderr.decode('utf-8')
return retVal
def OpenSSL_GenECDSAKeys(sBatchDir, sEcdsaKeyFile, sEcdsaPublicKeyDerFile,sEcdsaPublicKeyPemFile):
if os.path.isfile(sOPENSSL_BIN)!=True:
print("Cannot find OpenSSL.exe! " + sOPENSSL_BIN)
return false
if os.path.isfile(sEcdsaKeyFile)==True:
os.removefile (sEcdsaKeyFile)
try:
aGenKeyArgs = [' ecparam -genkey -name secp384r1 -out ' + sEcdsaKeyFile]
aGenKeyStatus = RunShellAndWait(sOPENSSL_BIN, aGenKeyArgs)
...
I concude that it is dropping into interactive mode because with stdout capture says "OpenSSL>" which is OpenSLL interactive prompt, i.e. I can just run OpenSSL.exe on its own and I get that prompt. Also the expected file is not generated.
I tried experiment with Popen but it did not like it. I am hoping someone has trodden this path before me and can point out a pitfall.
So the question is how to get OpenSSL to acknowledge and process the given arguments instead of dropping into interactive mode.
I have some code here trying to open up the cmd.exe from Python and input some lines for the command to use.
Here it is:
PDF= "myPDF"
output= "my output TIF"
def my_subprocess(command,c='C:\here'):
process = subprocess.Popen(command,stdout=subprocess.PIPE,shell=True,cwd=c)
communicate = process.communicate()[0].strip()
my_subprocess('"cmd.exe" && "C:\\here\\myinfamous.bat" && "C:\\my directory and lines telling cmd to do stuff"'+ PDF + " " + output)
When run with the rest of my script, the command prompt does not even open up and there seems to be no output or errors at all. My thought is that it has not even run the cmd.exe command so none of this code is going in to create the final output.
Is there something I am not doing properly?
Thank you.
You need to replace subprocess.Popen with subprocess.call
Here is a working code on windows 8 that opens a text file using notepad. First field is the command itself and second field is argument.
You can modify these and test with your files.
import subprocess
subprocess.call(['C:\\Windows\\System32\\Notepad.exe', 'C:\\openThisfile.txt'])
str = "blah -l"
cpuinfo = subprocess.Popen(str.split(),stdout=PIPE,stderr=PIPE)
tuples = cpuinfo.communicate()
In the above code, when I give str=[some_valid_command] gives the output to tuples. When I give an invalid command, I expect the error to be taken to PIPE, but it is still throwing out on the console.... I am not quite sure, where I understood it wrong....
Thanks.....
I'm not sure if you are seeing the stderr actually appear on the console, or are simply running into the Python failure to spawn a process named "blah", which is produced when running the example that you provided...
The output of the example would be Python raising an OSError: [Errno 2] No such file or directory, which is to be expected unless you have an executable script called "blah" in the PATH
I did a simple test, and wrote a bash script like this:
#!/bin/bash
echo "This is stdout"
echo "This is a failure on stderr" >&2
exit 1
After giving that script executable permissions, I repeated your example but instead called my script (named fail.sh in the local directory) as such:
import subprocess
cmd = './fail.sh'
proc = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE)
proc.communicate()
This returned ('This is stdout\n', 'This is a failure on stderr\n') as expected.
So perhaps what you're really seeing here is that whatever program you're trying to call (if it's not blah), simply doesn't exist on your PATH.
Also a note on using str as a label in Python: str is a built-in type and should not be used as a name for a variable or function, unless you specifically want to "over-load" the built-in function. Same goes for string, which is a class.