Running sequential command line arguments from python and retrieving output - python

I've been banging my head against the wall long enough, throwing in the towel here.
I am trying to use Python (specifically 3.8.2) to interface with a tool that has an ugly command line interface. I have the below command, which works. However, I've been reading up and it seems like this is a deprecated method, and they recommend using subprocess.run now. I've been trying convert my code over and having a lot of trouble, so hoping to find some help. Code below, along with an explanation.
os.system(rf'cmd /k "{ExecDrive}: & cd {ExecDirectory} & {command}"')
The first part of this is changing the drive letter and directory to a place where the programs executable is stored. Given a user could run this from any location, I have to ensure that they are in the right directory before running the command in the f-string below (which is essentially targetApp.exe -Arg1 Val1 -Arg2 Val2 etc.).
Second, I need to capture the output so I can parse it for some messages. I think I can figure that part out on my own if I can get the first part working, but if you're a subprocess.run pro, any help would be appreciated!

I was actually able to use the cwd command to accomplish what I needed. The new code is below.
subprocess.run(command, cwd=rf"{ExecDrive}:{ExecDirectory}", shell=True)

There is
subprocess.check_output(args)
for capturing output.
Reference: https://docs.python.org/3/library/subprocess.html#subprocess.check_output

Related

python script calling another script

I wrote a python script that works. The first line of my script is reading an hdf5 file
readFile = h5py.File('FileName_00','r')
After reading the file, my script does several mathematical operations, successfully working. In the output I got function F.
Now, I want to repeat the same script for different files. Basically, I only need to modify FileName_00 by FimeName_01 or ....FileName_10. I was thinking to create a script that call this script!
I never wrote a script that call another script, so any advice would be appreciable.
One option: turn your existing code into a function which takes a filename as an argument:
def myfunc(filename):
h5py.file(filename, 'r')
...
Now, after your existing code, call your function with the filenames you want to input:
myfunc('Filename_00')
myfunc('Filename_01')
myfunc('Filename_02')
...
Even more usefully, I definitely recommend looking into
if(__name__ == '__main__')
and argparse (https://docs.python.org/3/library/argparse.html) as jkr noted.
Also, if you put your algorithm in a function like this, you can import it and use it in another Python script. Very useful!
Although there are certainly many ways to achieve what you want without multiple python scripts, as other answerers have shown, here's how you could do it.
In python we have this function os.system (learn more about it here: https://docs.python.org/3/library/os.html#os.system). Simply put, you can use it like this:
os.system("INSERT COMMAND HERE")
Replacing INSERT COMMAND HERE with the command you use to run your python script. For example, with a script named script.py you could conceivably (depending on your environment) include the following line of code in a secondary python script:
os.system("python script.py")
Running the secondary python script would run script.py as well. FWIW, I don't necessarily think this is the best way to accomplish your goal -- I tend to agree with DraftyHat's solution in most circumstances. But in case you were curious, this is certainly an option in python. I've used this functionality in the past, albeit not to run other python scripts, but to execute commands in the shell. Hope this helps!

Python Subprocess with Complex Command

This question stems from my lack of knowledge surrounding the structure of UNIX commands and the SUBPROCESS module, so please forgive my naivete in advance.
I have a command, that looks something like this
path/to/openmpi/mpirun -machinefile machine.file -np 256 /path/to/excecutable </dev/null &> output.out &
I know how the structure of MPIrun works, and I think my executable writes its data to stdout and I redirect it to a file called output.out. I have used this command in python scripts using os.sys(), but I would like to use subprocess so that when the executable finished running (in the background), the python script can resume doing 'things.'
I have no idea where to start, so if someone has any tips or can show me the proper way to format the subprocess command, I would be really grateful. All personal attempts at using subprocess result in epic failures.
Thanks!!!
It's pretty straightforward.
from subprocess import call
call(["path/to/openmpi/mpirun", "-machinefile machine.file -np 256 /path/to/excecutable </dev/null &> output.out &"])
Generally, you'd provide the arguments to the command as a list, but I think this should work just as well. If not, break up each argument into a new element of the list.
This answer goes more into the limitations of this method.

Passing values from bash to python

I am trying to implement bash with python can anybody help me or teach me on what should be done.
my code is
import io
val=os.system("echo 'sdfsfs'") #for example
print(val)
The return value from os.system is an exit code of some kind (the exact details are platform-dependent), not the text the command it ran wrote to its to standard output stream.
To get that text, you need to use a different Python command to run the program. There are a few different options, and which is best depends on more details than you've given. I'd start with the subprocess module documentation, and pick the function that works best for what you need. The check_output function seems like a good first candidate.

Opening TOPCAT through command line Via Python Script

I'm trying to incorporate the program TOPCAT (which has really amazing plotting capabilities) into a python script I have written. The problem is that when I make a call to the program it tells me:
OSError: [Errno 2] No such file or directory
Here's some background to the problem:
1) The way I usually open up topcat through the command line is through the alias I have created:
alias topcat='java -jar /home/username/topcat/topcat-full.jar'
2) If I'd like to open TOPCAT with a file in mind (let's use a csv file since that's what I'd like it to work with), I would type this into the command line:
topcat -f csv /home/username/path_to_csv_file/file.csv
And that also works just fine. The problem comes about when I try to call these commands while in my python script. I've tried both subprocess.call and os.system, and they don't seem to know of the existence of the topcat alias for some reason. Even doing a simple call like:
import subprocess
subprocess.call(['topcat'])
doesn't work... However, I can get topcat to open if I run this:
import subprocess
subprocess.call(['java','-jar','/home/username/topcat/topcat-full.jar'])
The problem with this is that it simply opens the program, and doesn't allow for me to tell it which file to take in and what type it happens to be.
Could somebody tell me what I'm doing incorrectly here? I've also looked into the shell=True option and it doesn't seem to be doing any better.
Okay - so I'm really excited that figured it out. What worked before was:
import subprocess
subprocess.call(['java','-jar','/home/username/topcat/topcat-full.jar'])
It turns out it can take more command line arguments. This is what eventually got it open up with the correct comma separated file through the command line:
import subprocess
subprocess.call(['java','-jar','/home/username/topcat/topcat-full.jar','-f','csv','/full/path/to/data.csv'])
Hopefully this is enough information to help other people who come across this specific task.
If anyone else comes across this, pystilts might be of interest.
https://github.com/njcuk9999/pystilts
edit: It is a native Python wrapper of Topcat/STILTS.

python subprocess terminal mac osx

longtime lurker, first time poster.
I know there are quite a few examples throughout the interweb on using subprocess, however I am yet to find one that explains the steps I need to take to birth a new terminal window, and send it commands. There are plenty of posts that give workarounds to launch tools and scripts via a direct subprocess call, but I have not found any that actually answer the original questions of how to send a command properly to terminal.
In my case, I need to open a new terminal window, then send the path to a particular version of an application, and finally the path to the file I wish to open in that application.
I know how to use subprocess to call the applications needed directly (without opening a visible terminal), how to open a new terminal with subprocess, and how to call either the application path OR the file path (have not been able to get both to execute together using --args for open() or any other workaround I have found).
I have been unable to send terminal a command once I have opened it. The following is a simple version of opening a new instance of terminal and sending it ls, which does not work.
from subprocess import Popen, PIPE, STDOUT
p = Popen(['open', '-a', 'Terminal', '-n'], stdout=PIPE, stdin=PIPE, stderr=STDOUT)
output = p.communicate(input='ls')
print(output)
This is most likely a trivial issue and I am simply missing something, but I have been unable to find the information or an example that illustrates what I need and I am beginning to get frustrated with it, so I figured I would ask for help.
Any assistance is greatly appreciated! TIA
First, I doubt that command you are trying to run will run at all.
Did you try it in terminal first? open -an Terminal will give you
an error. It probably should be something like open -n
/Applications/Utilities/Terminal.app
Second, #korylprince is right: open itself will create new process
of Terminal and exit. So you are linking pipe with wrong process.
Third, at the moment of passing ls to the stdin that process
doesn't exist already (unless you will pass -W option to the open,
but it certainly will not help due to the 2 problem).
So I see only one opportunity to do this: via AppleScript. You can create an AppleScript string, something like next:
tell application "System Events"
tell process "Terminal"
keystroke "ls"
keystroke return
end tell
end tell
and then run this script via osascript -e '<your_script>' via Popen.
Yes it is quite tricky (I'd say it is a hack)
Yes there probably will be problems with passing multiline string to Popen and with determining correct Terminal window.
But it is possible.
#cody
My response to your answer was too long, therefore I am making an answer to respond:
You are correct, if you enter it the way you offered, it flags an error, and if you put the -n before Terminal it still flags an error. However, if you enter it the way I showed in the first example (-n after Terminal) "open" calls a new instance of app bundle Terminal, even if one is already open.
As for 2-3, that was kind of what my research was leading me to believe, but I was hoping I was wrong or missed something somewhere and someone here could clarify. Sadly, I wasn't mistaken…
I should probably expand on what I am trying to do, as maybe it will help generate a better way to accomplish it via Python.
I have created a tool that launches application files based on the movie, scene, and shot an artist is working on. For some applications, like Nuke and Houdini, opening from Terminal gives you a wealth of information that the artist would be blind to otherwise, so we would like to give the artist the option to launch the file they have chosen in a Terminal. That terminal has to be standalone, and a new instance of Terminal, because the app I have created must persist after the launch in order to open other shots in different applications without making the user routinely open the app.
Parsing the necessary info, building the commands, and launching a new Terminal that launches the desired application were all trivial. Doing the same with the desired file was trivial as well. The issue arises when a particular version of the app is chosen, and I have not been able to pass the newly birthed instance of Terminal with more than a single command (honestly the syntax of my OSX command may be the issue as well, will post further down).
I can get the following two commands to work without issue:
p = Popen(['open', '-a', 'Terminal', '-n', '--args', '/Applications/Nuke6.3v8/Nuke6.3v8.app/Nuke6.3v8'])
p = Popen(['open', '-a', 'Terminal', '-n', '--args', '/Path/to/Nuke/File.nk'])
I cannot get the following to work properly:
p = Popen(['open', '-a', 'Terminal', '-n', '--args', '/Applications/Nuke6.3v8/Nuke6.3v8.app/Nuke6.3v8', '/Path/to/Nuke/File.nk'])
From there my thought was possibly that I should launch the Terminal in the Popen, then pass the commands I needed. That did not work, and then I came here lol
Thanks again for any help! Just knowing that I cannot send to the commands I want to Terminal is saving me a ton of time that would have been spent on continuos frustrated research.

Categories

Resources