I have a script that gives the option to run a second script after completion. I am wondering if there is a good way for the second script to know if it was run on its own or as a subprocess. If it was called as a subprocess, pass args into the second script.
The end of the first script is below:
dlg = wx.MessageDialog(None, "Shall we format?",'Format Files',wx.YES_NO | wx.ICON_QUESTION)
result = dlg.ShowModal()
if result == wx.ID_YES:
call("Threading.py", shell=True)
else:
pass
The second script is a standalone script that takes 3 files and formats them into one. The args would just set file names in the second script.
So I would retrieve the parent process pid with os.getppid() and pass then this to the subprocess as arguments using Popen:
(parent.py)
#!/usr/bin/env python
import sys
import os
from subprocess import Popen, PIPE
output = Popen(['./child.py', str( os.getppid() )], stdout=PIPE)
print output.stdout.read()
and
(child.py)
#!/usr/bin/env python
import sys
import os
parent_pid = sys.argv[1]
my_pid = str(os.getppid())
print "Parent is %s child is %s " % ( parent_pid, my_pid )
So when you call the child from the parent
$ ./parent.py
Parent is 72297 child is 72346
At this point is easy to make a comparison and check the pid.
Related
I would like to know which window is hosting the terminal running Python. In specific, I would like to distinguish between windows terminal and the old CMD console on Windows machine.
EDIT:
I'm not sure I'm using correct words and there is an overload of words anyway. To be more specifc, I want to know the host window becaue they have different behaviours. Here's a photo of different windows, one of which Windows Terminal. powershell or cmd can be run in either of the windows, I'm interested in figuring out that window host.
If you use the psutil and os packages, you can use
parent_pid = os.getppid()
print(psutil.Process(parent_pid).name())
to get the parent process' name.
You could query WMI as I prefer to use OS tools (should work with psutil aswell, as mentioned by #BaguetteYeeter):
import os
import subprocess
import sys
print("Python interpreter: %s" % sys.executable)
parentShellName = None
# root process to look for parents until we find a process name
# which has not python in it's name
parentPid = os.getpid()
while 1:
# In case of ipython the second parent process is the Shell, so we are looping!
# Probably there should be a counter to finish the while loop in case no shell could be detected!
cmd = 'wmic process where "ProcessId=%s" get parentprocessid /format:list' % parentPid
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
out, err = proc.communicate()
key, parentPid = out.strip().decode('utf-8').split('=')
print("Parent ProcessId: %s" % parentPid)
cmd2 = 'wmic process where "ProcessId=%s" get name /format:list' % parentPid
proc = subprocess.Popen(cmd2, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
out, err = proc.communicate()
key, parentShellName = out.strip().decode('utf-8').split('=')
if 'python' not in parentShellName.lower():
break
print(parentShellName)
Out:
I am writing a program which initiates a connection to a remote machine, then dynamically sending multiple commands to it by monitoring the response. Instead of using pexpect, what else can I use? I am trying to use subprocess.Popen, but communicate() method will kill the process.
Pexpect version: 2.4, http://www.bx.psu.edu/~nate/pexpect/pexpect.html
Referring to the API for subprocess in:
https://docs.python.org/2/library/subprocess.html#subprocess.Popen.communicate
Popen.communicate(input=None)
Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate. The optional input argument should be a string to be sent to the child process, or None, if no data should be sent to the child.
Thanks
Refer the subprocess documentation to understand the basics here
You could do something like this ...
Again, this is just a pointer... this approach may/may not be a best fit for your use case.
Explore -> and Test to find what works for you!
import shlex
import subprocess
import sys
class Command(object):
""" Generic Command Interface ."""
def execute(self, cmd):
proc = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE)
stdout_value = proc.communicate()[0]
exit_value = proc.poll()
if exit_value:
logger.error('Command execution failed. Command : %s' % cmd)
return exit_value, stdout_value
if __name__ == '__main__':
cmd = Command()
host = '' # HOSTNAME GOES HERE
cmd_str = '' # YOUR COMMAND GOES HERE
cmdline = 'ksh -c "ssh root#{0} "{1}""'.format(host, cmd_str)
exit_value, stdout_value = cmd.execute(cmdline)
if exit_value == 0:
# execute other command/s
# you basically use the same logic as above
else:
# return Or execute other command/s
There is a way to start another script in python by doing this:
import os
os.system("python [name of script].py")
So how can i stop another already running script? I would like to stop the script by using the name.
It is more usual to import the other script and then invoke its functions and methods.
If that does not work for you, e.g. the other script is not written in such a way that is conducive to being imported, then you can use the subprocess module to start another process.
import subprocess
p = subprocess.Popen(['python', 'script.py', 'arg1', 'arg2'])
# continue with your code then terminate the child
p.terminate()
There are many possible ways to control and interact with the child process, e.g. you can can capture its stdout and sterr, and send it input. See the Popen() documentation.
If you start the script as per mhawkes suggestion is it a better option but to answer your question of how to kill an already started script by name you can use pkill and subprocess.check_call:
from subprocess import check_call
import sys
script = sys.argv[1]
check_call(["pkill", "-9", "-f", script])
Just pass the name to kill:
padraic#home:~$ cat kill.py
from subprocess import check_call
import sys
script = sys.argv[1]
check_call(["pkill", "-9", "-f", script])
padraic#home:~$ cat test.py
from time import sleep
while True:
sleep(1)
padraic#home:~$ python test.py &
[60] 23361
padraic#home:~$ python kill.py test.py
[60] Killed python test.py
Killed
That kills the process with a SIGKIll, if you want to terminate remove the -9:
padraic#home:~$ cat kill.py
from subprocess import check_call
import sys
script = sys.argv[1]
check_call(["pkill", "-f", script])
padraic#home:~$ python test.py &
[61] 24062
padraic#home:~$ python kill.py test.py
[61] Terminated python test.py
Terminated
That will send a SIGTERM. Termination-Signals
Just put in the name of the program NOT the path to your script.
so it would be
check_call(["pkill", "-f", "MotionDetector.py"])
I am downloading a file using wget in Python using the code below:
p1 = subprocess.Popen(['wget',
'-P',
'path/to/folder','http://www.ncbi.nlm.nih.gov/Traces/wgs/?download=ACHI01.1.fsa_nt.gz'],
stdout=subprocess.PIPE)
p1.studout.close()
The file gets downloaded and saved correctly in the given folder but the process keeps running. I tried p1.kills() but that doesn't work either.
Please advise.
Thanks!
Use subprocess.call
import subprocess
subprocess.call (['wget', '-P', '/', 'http://www.ncbi.nlm.nih.gov/Traces/wgs/?download=ACHI01.1.fsa_nt.gz'])
A call to wait() is missing after the Popen, to make the main process wait till the child process is terminated.. The following code seems to work fine:
import subprocess as sp
def main(args):
p1 = sp.Popen(['wget', '-P path',
'http://www.ncbi.nlm.nih.gov/Traces/wgs/?download=ACHI01.1.fsa_nt.gz'],
stdout = sp.PIPE)
p1.wait()
return 0
if __name__ == '__main__':
import sys
sys.exit(main(sys.argv))
(You can also group commandline parameters with their values, if they have any).
I'm trying to use LocalPath.sysexec() from the py library, but the documentation is not clear enough for me to understand how to invoke it with the right syntax.
Here is some fake code that mimics my syntax:
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Testing pylib implementation of subprocess.Popen
from py.path import local
import sys
path = local(sys.argv[1])
path.sysexec("/usr/bin/foo", ["arg1", "arg2"])
You can look the source code:
def sysexec(self, *argv, **popen_opts):
""" return stdout text from executing a system child process,
where the 'self' path points to executable.
The process is directly invoked and not through a system shell.
"""
from subprocess import Popen, PIPE
argv = map_as_list(str, argv)
popen_opts['stdout'] = popen_opts['stderr'] = PIPE
proc = Popen([str(self)] + argv, **popen_opts)
stdout, stderr = proc.communicate()
ret = proc.wait()
if py.builtin._isbytes(stdout):
stdout = py.builtin._totext(stdout, sys.getdefaultencoding())
if ret != 0:
if py.builtin._isbytes(stderr):
stderr = py.builtin._totext(stderr, sys.getdefaultencoding())
raise py.process.cmdexec.Error(ret, ret, str(self),
stdout, stderr,)
return stdout
clearly, It use the python subprocess module. If you have not been used subprocess, you can click the above link to raed the docs.
In this function, It use subprocess construct a Popen object, and use the argv you pass.
Then call the Popen.wait(), block until the command execute finish. And return the stdout of the command.
Example:
local_path = py._path.local.LocalPath('/usr/bin/ls')
print(local_path.sysexec())
# out: file1\nfile2\nfile3...
print(local_path.sysexec('-l'))
# out likes "ls -l" out