I'm working on a script to send a list of commands to a device and return the output.
When the device first boots up, it has a few prompts. I am able to get through the prompts.
However, after completing the prompts, when I try to send a command the command isn't sent.
Commands
The commands.txt is set up like this:
200,
2,no
2,
The first line (200) is to let the device boot up.
The 2nd and 3rd lines answer 2 different prompts.
Issues
The issues come after these 3 inputs. The code runs and completes. Python prints out each of the commands. So the list is processed by Python. However, I don't think the device is receiving the commands.
In the log, the \n and no are written out, but none of the commands after it are. The commands do show when I use ser.inWaiting()
When I access the device through putty and run the commands through the console, everything works as expected.
Why aren't the commands going through?
Small update:
I read somewhere that python may be sending the commands to quickly, so I tried sending the commands 1 char at a time with a .01 delay.
It still didn't work:
for i in lines[1]:
cmd = i
encoded_cmd = cmd.encode("utf-8")
ser.write(encoded_cmd)
sleep(0.1)
print(cmd)
Code
import serial
import time
from time import sleep
from datetime import datetime
# create list of commands
with open('commands.txt') as commands:
list_of_commands = [tuple(map(str, i.split(','))) for i in commands]
# open and name log file
date = datetime.now().strftime("%Y-%m-%d")
log = open(f'{date}.txt', 'w+')
# serial configuration
info = open('info.txt', 'r')
lines = info.readlines()
port = lines[0].strip('\n')
baud = int(lines[1].strip('\n'))
try:
# open port
ser = serial.Serial(port=port, baudrate=baud, timeout=5, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, write_timeout=0)
except ConnectionError:
log.write(''.join('There was a connection error'))
else:
# run commands
x = 0
for lines in list_of_commands:
ser.close()
ser.open()
sleep(2)
cmd = lines[1]
encoded_cmd = cmd.encode("utf-8")
sleep_time = int(lines[0])
ser.write(encoded_cmd)
time.perf_counter()
# log output
while 1:
test = ser.readline()
text = test.decode('utf-8')
print(text)
log.write(''.join(text))
print(time.perf_counter())
print(time.perf_counter() - x)
if time.perf_counter() - x > sleep_time:
x = time.perf_counter()
ser.flushInput()
ser.flushOutput()
break
print(cmd)
# close port
ser.close()
# close files
log.close()
From the question it's obvious that multiple issues are intermingled. The same observation comes when reading the code. So I tried to list some of those I struggled with.
Issues
Try-except-else
What is the intention behind try .. except .. else ?
Not sure, its used correctly on purpose here. See try-except-else explained:
The else clause is executed if and only if no exception is raised. This is different from the finally clause that’s always executed.
The serial connection
Why opening and closing inside the loop:
ser.close()
ser.open()
Why the misleading comment:
# close server
ser.close()
Usage of sleep_time
What is the purpose of using the first column sleep_time of your CSV commands.txt inside a conditional break inside you read-loop?
sleep_time = int(lines[0])
Instead the sleep is fix 2 seconds before sending the command:
sleep(2)
How to debug
I would recommend adding some print (or log) statements to
verify the list_of_commands has been read correctly
verify which commands (cmd or even encoded_cmd) have been sent to the serial output
I want to write a Python script which will check every minute if some pre-defined process is still running on Linux machine and if it doesn't print a timestamp at what time it has crashed. I have written a script which is doing exactly that but unfortunately, it works correctly with only one process.
This is my code:
import subprocess
import shlex
import time
from datetime import datetime
proc_def = "top"
grep_cmd = "pgrep -a " + proc_def
try:
proc_run = subprocess.check_output(shlex.split(grep_cmd)).decode('utf-8')
proc_run = proc_run.strip().split('\n')
'''
Creating a dictionary with key the PID of the process and value
the command line
'''
proc_dict = dict(zip([i.split(' ', 1)[0] for i in proc_run],
[i.split(' ', 1)[1] for i in proc_run]))
check_run = "ps -o pid= -p "
for key, value in proc_dict.items():
check_run_cmd = check_run + key
try:
# While the output of check_run_cmd isn't empty line do
while subprocess.check_output(
shlex.split(check_run_cmd)
).decode('utf-8').strip():
# This print statement is for debugging purposes only
print("Running")
time.sleep(3)
'''
If the check_run_cmd is returning an error, it shows us the time
and date of the crash as well as the PID and the command line
'''
except subprocess.CalledProcessError as e:
print(f"PID: {key} of command: \"{value}\" stopped
at {datetime.now().strftime('%d-%m-%Y %T')}")
exit(1)
# Check if the proc_def is actually running on the machine
except subprocess.CalledProcessError as e:
print(f"The \"{proc_def}\" command isn't running on this machine")
For example, if there are two top processes it will show me information about the crash time of only one of these processes and it will exit. I want to stay active as long as there is another process running and exit only if both processes are killed. It should present information when each of the processes has crashed.
It shall also not be limited to two proc only and support multiple processes started with the same proc_def command.
Have to change the logic a bit, but basically you want an infinite loop alternating a check on all processes - not checking the same one over and over:
import subprocess
import shlex
import time
from datetime import datetime
proc_def = "top"
grep_cmd = "pgrep -a " + proc_def
try:
proc_run = subprocess.check_output(shlex.split(grep_cmd)).decode('utf-8')
proc_run = proc_run.strip().split('\n')
'''
Creating a dictionary with key the PID of the process and value
the command line
'''
proc_dict = dict(zip([i.split(' ', 1)[0] for i in proc_run],
[i.split(' ', 1)[1] for i in proc_run]))
check_run = "ps -o pid= -p "
while proc_dict:
for key, value in proc_dict.items():
check_run_cmd = check_run + key
try:
# While the output of check_run_cmd isn't empty line do
subprocess.check_output(shlex.split(check_run_cmd)).decode('utf-8').strip()
# This print statement is for debugging purposes only
print("Running")
time.sleep(3)
except subprocess.CalledProcessError as e:
print(f"PID: {key} of command: \"{value}\" stopped at {datetime.now().strftime('%d-%m-%Y %T')}")
del proc_dict[key]
break
# Check if the proc_def is actually running on the machine
except subprocess.CalledProcessError as e:
print(f"The \"{proc_def}\" command isn't running on this machine")
This suffers from the same problems in the original code, namely the time resolution is 3 seconds, and if a new process is run during this script, you won't ping it (though this may be desired).
The first problem would be fixed by sleeping for less time, depending on what you need, the second by running the initial lines creating proc_dict in the while True.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
This is my code so far:
import subprocess
def __init__(pingcount, hostname):
try:
out, error = subprocess.Popen.communicate(subprocess.Popen("ping -n " + pingcount + ' ' + hostname), timeout=10)
except subprocess.TimeoutExpired:
subprocess.Popen.kill(subprocess.Popen)
return "No connection to terminal. Contact system administrator."
print(str(out))
if str(out).find("rtt") != -1:
return str(out)[str(out).find("rtt"):]
else:
return "No connection to server."
Similar code works on Windows, but upon calling this function, I get a return value of None.
From PING(8) man page in Linux:
-c count Stop after sending count ECHO_REQUEST packets. With deadline option, ping waits for count ECHO_REPLY packets, until the timeout expires.
-n Numeric output only. No attempt will be made to lookup symbolic names for host addresses.
You're passing -n argument as a result the command fails in Linux:
$ ping -n 10 www.google.com
connect: Invalid argument
from subprocess import Popen, PIPE, TimeoutExpired
import sys
# inside class body
def __init__(pingcount, hostname):
if sys.platform == "linux":
cmd = ["ping", "-c", pingcount, hostname]
else:
cmd = "ping -n " + pingcount + ' ' + hostname # else: assume Windows
proc = Popen(cmd, stdout=PIPE, stderr=PIPE)
try:
proc_stdout, proc_stderr = proc.communicate(timeout=19)
except TimeoutExpired:
proc.kill() # on Linux send SIGKILL signal
return "No connection to terminal. Contact system administrator."
# rest of code...
The if statement at the beginning simply checks the operating system on which Python is running to determined the right command to pass to Popen.
Note: using proc.kill send SIGTERM on POSIX operating systems like Linux. This is a very brutal way to kill the process. The operating system will forcibly terminate the process and remove it from memory. Probably you need to use proce.terminate instead. However, I don't see serious implications here for using proc.kill with ping. see Popen.kill section in the documentation of the subprocess module.
I m trying to execute several batch-scripts in a python loop. However the said bat-scripts contain cmd /K and thus do not "terminate" (for lack of a better word). Therefore python calls the first script and waits forever...
Here is a pseudo-code that gives an idea of what I am trying to do:
import subprocess
params = [MYSCRIPT, os.curdir]
for level in range(10):
subprocess.call(params)
My question is: "Is there a pythonic solution to get the console command back and resume looping?"
EDIT: I am now aware that it is possible to launch child processes and continue without waiting for them to return, using
Popen(params,shell=False,stdin=None,stdout=None,stderr=None,close_fds=True)
However this would launch my entire loop almost simultaneously. Is there a way to wait for the child process to execute its task and return when it hits the cmd /K and becomes idle.
There is no built in way, but it's something you can implement.
Examples are with bash since I don't have access to a Windows machine, but should be similar for cmd \K
It might be as easy as:
import subprocess
# start the process in the background
process = subprocess.Popen(
['bash', '-i'],
stdout=subprocess.PIPE,
stdin=subprocess.PIPE
)
# will throw IO error if process terminates by this time for some reason
process.stdin.write("exit\n")
process.wait()
This will send an exit command to the shell, which should be processed just as the script terminates causing it to exit ( effectively canceling out the \K )
Here's a more elaborate answer in case you need a solution that checks for some output:
import subprocess
# start the process in the background
process = subprocess.Popen(
['bash', '-i'],
stdout=subprocess.PIPE,
stdin=subprocess.PIPE
)
# Wait for the process to terminate
process.poll()
while process.returncode is None:
# read the output from the process
# note that can't use readlines() here as it would block waiting for the process
lines = [ x for x in process.stdout.read(5).split("\n") if x]
if lines:
# if you want the output to show, you'll have to print it yourself
print(lines )
# check for some condition in the output
if any((":" in x for x in lines)):
# terminate the process
process.kill()
# alternatively could send it some input to have it terminate
# process.stdin.write("exit\n")
# Check for new return code
process.poll()
The complication here is with reading the output, as if you try to read more than is available, the process will block.
Here is something I use where I start a bunch of processes (2 in this example) and wait for them at the end before the program terminates. It can be modified to wait for specific processes at different times (see comments). In this example one process prints out the %path% and the other prints the directory contents.
import win32api, win32con, win32process, win32event
def CreateMyProcess2(cmd):
''' create process width no window that runs sdelete with a bunch of arguments'''
si = win32process.STARTUPINFO()
info = win32process.CreateProcess(
None, # AppName
cmd, # Command line
None, # Process Security
None, # Thread Security
0, # inherit Handles?
win32process.NORMAL_PRIORITY_CLASS,
None, # New environment
None, # Current directory
si) # startup info
return info[0]
# info is tuple (hProcess, hThread, processId, threadId)
if __name__ == '__main__' :
handles = []
cmd = 'cmd /c "dir/w"'
handle = CreateMyProcess2(cmd)
handles.append(handle)
cmd = 'cmd /c "path"'
handle = CreateMyProcess2(cmd)
handles.append(handle)
rc = win32event.WaitForMultipleObjects(
handles, # sequence of objects (here = handles) to wait for
1, # wait for them all (use 0 to wait for just one)
15000) # timeout in milli-seconds
print rc
# rc = 0 if all tasks have completed before the time out
Approximate Output (edited for clarity):
PATH=C:\Users\Philip\algs4\java\bin;C:\Users\Philip\bin;C:\Users\Philip\mksnt\ etc......
Volume in drive C has no label.
Volume Serial Number is 4CA0-FEAD
Directory of C:\Users\Philip\AppData\Local\Temp
[.]
[..]
FXSAPIDebugLogFile.txt
etc....
1 File(s) 0 bytes
3 Dir(s) 305,473,040,384 bytes free
0 <-- value of "rc"
I am trying to create a python script which I will later run as a service. Now I want to run a particular part of the code only when iTunes is running. I understand from some research that polling the entire command list and then searching for the application for that list is expensive.
I found out that processes on UNIX-based operating systems create a lock file to notify that a program is currently running, at which point we can use os.stat(location_of_file) to check if the file exists to determine if a program is running or not.
Is there a similar lock file created on Windows?
If not what are the various ways in Python by which we can determine if a process is running or not?
I am using python 2.7 and iTunes COM interface.
You can not rely on lock files in Linux or Windows. I would just bite the bullet and iterate through all the running programs. I really do not believe it will be as "expensive" as you think. psutil is an excellent cross-platform python module cable of enumerating all the running programs on a system.
import psutil
"someProgram" in (p.name() for p in psutil.process_iter())
Although #zeller said it already here is an example how to use tasklist. As I was just looking for vanilla python alternatives...
import subprocess
def process_exists(process_name):
call = 'TASKLIST', '/FI', 'imagename eq %s' % process_name
# use buildin check_output right away
output = subprocess.check_output(call).decode()
# check in last line for process name
last_line = output.strip().split('\r\n')[-1]
# because Fail message could be translated
return last_line.lower().startswith(process_name.lower())
and now you can do:
>>> process_exists('eclipse.exe')
True
>>> process_exists('AJKGVSJGSCSeclipse.exe')
False
To avoid calling this multiple times and have an overview of all the processes this way you could do something like:
# get info dict about all running processes
import subprocess
output = subprocess.check_output(('TASKLIST', '/FO', 'CSV')).decode()
# get rid of extra " and split into lines
output = output.replace('"', '').split('\r\n')
keys = output[0].split(',')
proc_list = [i.split(',') for i in output[1:] if i]
# make dict with proc names as keys and dicts with the extra nfo as values
proc_dict = dict((i[0], dict(zip(keys[1:], i[1:]))) for i in proc_list)
for name, values in sorted(proc_dict.items(), key=lambda x: x[0].lower()):
print('%s: %s' % (name, values))
win32ui.FindWindow(classname, None) returns a window handle if any window with the given class name is found. It raises window32ui.error otherwise.
import win32ui
def WindowExists(classname):
try:
win32ui.FindWindow(classname, None)
except win32ui.error:
return False
else:
return True
if WindowExists("DropboxTrayIcon"):
print "Dropbox is running, sir."
else:
print "Dropbox is running..... not."
I found that the window class name for the Dropbox tray icon was DropboxTrayIcon using Autohotkey Window Spy.
See also
MSDN FindWindow
Lock files are generally not used on Windows (and rarely on Unix). Typically when a Windows program wants to see if another instance of itself is already running, it will call FindWindow with a known title or class name.
def iTunesRunning():
import win32ui
# may need FindWindow("iTunes", None) or FindWindow(None, "iTunes")
# or something similar
if FindWindow("iTunes", "iTunes"):
print "Found an iTunes window"
return True
I'd like to add this solution to the list, for historical purposes. It allows you to find out based on .exe instead of window title, and also returns memory used & PID.
processes = subprocess.Popen('tasklist', stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE).communicate()[0]
# Put a regex for exact matches, or a simple 'in' for naive matches
A slice of example output:
notepad.exe 13944 Console 1 11,920 K
python.exe 5240 Console 1 28,616 K
conhost.exe 9796 Console 1 7,812 K
svchost.exe 1052 Services 0 18,524 K
iTunes.exe 1108 Console 1 157,764 K
Try this code:
import subprocess
def process_exists(process_name):
progs = str(subprocess.check_output('tasklist'))
if process_name in progs:
return True
else:
return False
And to check if the process is running:
if process_exists('example.exe'):
#do something
Psutil suggested by Mark, is really the best solution, its only drawback is the GPL compatible license. If that's a problem, then you can invoke Windows' process info commands: wmic process where WMI is available (XP pro, vista, win7) or tasklist. Here is a description to do it: How to call an external program in python and retrieve the output and return code? (not the only possible way...)
import psutil
for p in psutil.process_iter(attrs=['pid', 'name']):
if "itunes.exe" in (p.info['name']).lower():
print("yes", (p.info['name']).lower())
for python 3.7
import psutil
for p in psutil.process_iter(attrs=['pid', 'name']):
if p.info['name'] == "itunes.exe":
print("yes", (p.info['name']))
This works for python 3.8 & psutil 5.7.0, windows
Would you be happy with your Python command running another program to get the info?
If so, I'd suggest you have a look at PsList and all its options. For example, The following would tell you about any running iTunes process
PsList itunes
If you can work out how to interpret the results, this should hopefully get you going.
Edit:
When I'm not running iTunes, I get the following:
pslist v1.29 - Sysinternals PsList
Copyright (C) 2000-2009 Mark Russinovich
Sysinternals
Process information for CLARESPC:
Name Pid Pri Thd Hnd Priv CPU Time Elapsed Time
iTunesHelper 3784 8 10 229 3164 0:00:00.046 3:41:05.053
With itunes running, I get this one extra line:
iTunes 928 8 24 813 106168 0:00:08.734 0:02:08.672
However, the following command prints out info only about the iTunes program itself, i.e. with the -e argument:
pslist -e itunes
If can't rely on the process name like python scripts which will always have python.exe as process name. If found this method very handy
import psutil
psutil.pid_exists(pid)
check docs for further info
http://psutil.readthedocs.io/en/latest/#psutil.pid_exists
According to the ewerybody post: https://stackoverflow.com/a/29275361/7530957
Multiple problems can arise:
Multiple processes with the same name
Name of the long process
The 'ewerybody's' code will not work if the process name is long. So there is a problem with this line:
last_line.lower().startswith(process_name.lower())
Because last_line will be shorter than the process name.
So if you just want to know if a process/processes is/are active:
from subprocess import check_output
def process_exists(process_name):
call = 'TASKLIST', '/FI', 'imagename eq %s' % process_name
if check_output(call).splitlines()[3:]:
return True
Instead for all the information of a process/processes
from subprocess import check_output
def process_exists(process_name):
call = 'TASKLIST', '/FI', 'imagename eq %s' % process_name
processes = []
for process in check_output(call).splitlines()[3:]:
process = process.decode()
processes.append(process.split())
return processes
There is a python module called wmi.
import wmi
c=wmi.WMI()
def check_process_running(str_):
if(c.Win32_Process(name=str_)):
print("Process is running")
else:
print("Process is not running")
check_process_running("yourprocess.exe")
I liked the solution of #ewerybody with this little change
import subprocess
def process_exists(process_name):
call = 'TASKLIST', '/FI', 'imagename eq %s' % process_name
# use buildin check_output right away
output = subprocess.check_output(call).decode()
# check in last line for process name
last_line = output.split('\r\n')
#first result is 3 because the headers
#or in case more than one, you can use the last one using [-2] index
data = " ".join(last_line[3].split()).split()
#return a list with the name and pid
return( [data[0], data[1]] )
This method below can be used to detect whether the process [ eg: notepad.exe ] is runing or not.
from pymem import Pymem
import pymem
while (True):
try:
pm = Pymem('notepad.exe')
print('Notepad Started And Is Running....')
except:
print ('Notepad Is Not Running....')
Pymem Package Is Needed. To Install It,
pip install pymem
This works nicely
def running():
n=0# number of instances of the program running
prog=[line.split() for line in subprocess.check_output("tasklist").splitlines()]
[prog.pop(e) for e in [0,1,2]] #useless
for task in prog:
if task[0]=="itunes.exe":
n=n+1
if n>0:
return True
else:
return False
If you are testing application with Behave you can use pywinauto.
Similar with previously comment, you can use this function:
def check_if_app_is_running(context, processName):
try:
context.controller = pywinauto.Application(backend='uia').connect(best_match = processName, timeout = 5)
context.controller.top_window().set_focus()
return True
except pywinauto.application.ProcessNotFoundError:
pass
return False
backend can be 'uia' or 'win32'
timeout if for force reconnect with the applicaction during 5 seconds.
import subprocess as sp
for v in str(sp.check_output('powershell "gps | where {$_.MainWindowTitle}"')).split(' '):
if len(v) is not 0 and '-' not in v and '\\r\\' not in v and 'iTunes' in v: print('Found !')
import psutil
def check_process_status(process_name):
"""
Return status of process based on process name.
"""
process_status = [ proc.status() for proc in psutil.process_iter() if proc.name() == process_name ]
if process_status:
print("Process name %s and staus %s"%(process_name, process_status[0]))
else:
print("Process name not valid", process_name)
Psutil is the best solution for this.
import psutil
processes = list(p.name() for p in psutil.process_iter())
# print(processes)
count = processes.count("<app_name>.exe")
if count == 1:
logging.info('Application started')
# print('Application started')
else:
logging.info('Process is already running!')
# print('Process is already running!')
sys.exit(0) # Stops duplicate instance from running
You can just use os.kill sending a 0 signal (that doesn't kill the process) and checking for errors.
from os import kill
def check_if_running(pid):
try:
kill(pid, 0)
except:
return False
return True