I have written a script that checks if an SVN Repo is up and running, the result is based on the return value.
import subprocess
url = " validurl"
def check_svn_status():
subprocess.call(['svn info'+url],shell=True)
def get_status():
subprocess.call('echo $?',shell=True)
def main():
check_svn_status()
get_status()
if __name__ == '__main__':
main()
The problem I'm facing is that if I change the url to something that does't exist I still get the return value as 0, but if I were to run this outside the script, i.e go to the terminal type svn info wrong url and then do a echo $? I get a return value of 1. But I can't re-create this in the python. Any guidelines ?
TraceBack after updating
Traceback (most recent call last):
File "svn_status.py", line 21, in <module>
main()
File "svn_status.py", line 15, in main
check_svn_status()
File "svn_status.py", line 8, in check_svn_status
p = sp.Popen(['svn info'], stdout=sp.PIPE, stderr=sp.PIPE)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 672, in __init__
errread, errwrite)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 1202, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or director
y
Why your approach does not work:
You invoke two independent subshells. The second shell does not know of the first shell and therefore does not have any information about the returncode of the process that was executed in the first shell.
Solution:
Use the subprocess module, spawn your subprocess directly (not through a subshell) and retrieve the returncode. Help yourself by reading the documentation of the module: http://docs.python.org/library/subprocess.html
There are several ways to achieve your goal. One simple way could be:
import subprocess as sp
p = sp.Popen(['command', 'arg1', 'arg2'], stdout=sp.PIPE, stderr=sp.PIPE)
stdout, stderr = p.communicate()
returncode = p.returncode
This way, you don't go through a subshell (shell=False by default), which is the recommended approach for various reasons. You directly catch the returncode of the spawned subprocess and you have full access to the subprocess' standard output and standard error.
subprocess.call returns the retcode, just store the result of your subprocess.call(['svn info'+url],shell=True)
http://docs.python.org/library/subprocess.html
Related
stackoverflow community!
I use python3 to collect some information from a server, but I had this Error and I did not find a solution for it.
This is my code below :
from subprocess import check_output
disks = check_output(("df")).decode("utf-8").split('\n')
print(disks)
and this is the output:
df: /run/user/1001/doc: Operation not permitted
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "/usr/lib/python3.9/subprocess.py", line 424, in check_output
return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
File "/usr/lib/python3.9/subprocess.py", line 528, in run
raise CalledProcessError(retcode, process.args,
subprocess.CalledProcessError: Command 'df' returned non-zero exit status 1.
check_output() it work with other commands for example: check_output(("uname")).decode("utf-8") the output is: Linux
Why it work with other commands, but it don't work with df command? and what is the solution for this problem?
the command df it work when I run it from the terminal
Your Python code is fine as such. If you want to avoid the traceback, subprocess.run lets you do that.
from subprocess import run
disks = run(["df"], capture_output=True, text=True)
print(disks.stdout)
The check in check_output means specifically that Python will raise an error if the subprocess fails.
But Python is not doing anything useful here. Simply
import subprocess
subprocess.call(["df"])
would do the same thing with less hassle. (Running df without Python would obviously be more straightforward still.)
It looks like you have a permissions error. You could probably get a better error indication by doing that directly in Python. The following function does the equivalent.
import os
def df(path="/"):
"""Return file system blocks used and free.
Values are same as output of df command.
"""
stat = os.statvfs(path)
return (((stat.f_blocks - stat.f_bfree) * 8),
(stat.f_bavail * (stat.f_frsize // 512)))
I am running into following error when trying to run a command using Popen,what is wrong here?
cmd = "export COMMANDER_SERVER=commander.company.com"
Pipe = Popen(cmd, stdout=PIPE, stderr=PIPE)
(output, error) = Pipe.communicate()
Error:-
Traceback (most recent call last):
File "test_ectool.py", line 26, in <module>
main()
File "test_ectool.py", line 13, in main
Pipe = Popen(cmd, stdout=PIPE, stderr=PIPE)
File "/usr/lib/python2.7/subprocess.py", line 679, in __init__
errread, errwrite)
File "/usr/lib/python2.7/subprocess.py", line 1249, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory
You need to separate the arguments from the command and give a list to Popen.
As Kenster's comment said, even if your command worked, you would only succeed in modifying an environmental variable inside a sub-shell not the main shell.
You will not be able run run export this way, because it is not a program. It is a bash built-in.
Here is an example of a command that does work, with the correct semantics.
from subprocess import Popen,PIPE
cmd = "echo COMMANDER_SERVER=commander.company.com"
Pipe = Popen(cmd.split(), stdout=PIPE, stderr=PIPE)
(output, error) = Pipe.communicate()
print output
merlin2011's answer is incorrect regarding the command string for Popen (point #1). From the Python docs:
args should be a sequence of program arguments or else a single string.
As other people have stated, the environment variable will not be saved. For that, you need to use os.environ['VARNAME'] = value. If you want to use other bash builtins, then you must pass shell=True as an argument to Popen.
I am trying to save the result or function runcmd in the variable Result.
Here is what I have tried:
import subprocess
def runcmd(cmd):
x = subprocess.Popen(cmd, stdout=subprocess.PIPE)
Result = x.communicate(stdout)
return Result
runcmd("dir")
When I run ths code, I get this result:
Traceback (most recent call last):
File "C:\Python27\MyPython\MyCode.py", line 7, in <module>
runcmd("dir")
File "C:\Python27\MyPython\MyCode.py", line 4, in runcmd
x = subprocess.Popen(cmd, stdout=subprocess.PIPE)
File "C:\Python27\lib\subprocess.py", line 679, in __init__
errread, errwrite)
File "C:\Python27\lib\subprocess.py", line 893, in _execute_child
startupinfo)
WindowsError: [Error 2] The system cannot find the file specified
What could I do to fix this?
I think what you are looking for is os.listdir()
check out the os module for more info
an example:
>>> import os
>>> l = os.listdir()
>>> print (l)
['DLLs', 'Doc', 'google-python-exercises', 'include', 'Lib', 'libs', 'LICENSE.txt', 'NEWS.txt', 'python.exe', 'pythonw.e
xe', 'README.txt', 'tcl', 'Tools', 'VS2010Cmd.lnk']
>>>
You could also read the output into a list:
result = []
process = subprocess.Popen('dir',
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE )
for line in process.stdout:
result.append(line)
errcode = process.returncode
for line in result:
print(line)
As far as I know, dir is a built in command of the shell in Windows and thus not a file available for execution as a program. Which is probably why subprocess.Popen cannot find it. But you can try adding shell=True to the Popen() construtor call like this:
def runcmd(cmd):
x = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
return x.communicate(stdout)
runcmd("dir")
If shell=True doesn't help, you're out of luck executing dir directly. But then you can make a .bat file and put a call to dir there instead, and then invoke that .bat file from Python instead.
btw also check out the PEP8!
P.S As Mark Ransom pointed out in a comment, you could just use ['cmd', '/c', 'dir'] as the value of cmd instead of the .bat hack if shell=True fails to fix the issue.
I have a script in which I use subprocess.Popen to start an external program and process.kill() to kill it pretty much as soon as it's started. I've been getting Windows Error [5] (Access Denied) every time the script tries to kill it. I've realized that the pid of the program is actually changing after it's opened. Is there a way, in Python, to monitor the process for the change, or to just retrieve the new pid?
Here is the code:
import subprocess
import time
proc = subprocess.Popen(Path/to/WinSCP.exe)
time.sleep(2)
proc.kill()
The error:
Traceback (most recent call last):
File "C:\Python27\lib\lib-tk\Tkinter.py", line 1410, in __call__
return self.func(*args)
File "C:\Path", line 231, in __call__
self.scpsetup()
File "C:\Path", line 329, in scpsetup
proc.kill()
File "C:\Python27\lib\subprocess.py", line 1019, in terminate
_subprocess.TerminateProcess(self._handle, 1)
WindowsError: [Error 5] Access is denied
This is what I ended up doing;
import tempfile
import subprocess
import time
# Create a temp file to receive output
tf = tempfile.NamedTemporaryFile(delete=False)
output = open(tf.name, "w")
# Open and close WinSCP
subprocess.Popen(Path/To/WinSCP.exe)
time.sleep(2)
subprocess.call("TASKKILL /IM WinSCP.exe", stdout=output)
tf.close()
The issue I had with methods like this before was that I couldn't hide the output of the command. This may not be the prettiest way to accomplish this but it works.
Also note that I am using Windows 8. I understand that the command itself may vary slightly in different versions of Windows.
I want to delete a number of jobs from a q. The command to delete the job is qdel JOBid.
Initially, I tried to use the subprocess module, but I got an error:
#!/usr/bin/env python
import sys, os, subprocess as sp
lo = sys.argv[1]
hi = sys.argv[2]
lo = int(lo)
hi = int(hi)
for i in range(lo,hi):
print "i is %d"%i
p=sp.Popen(['qdel %d'%i],stdout=sp.PIPE)
#os.system('qdel %d'%i)
So this did not work. The error I got was
Traceback (most recent call last):
File "del.py", line 14, in <module>
p=sp.Popen(['qdel %d'%i],stdout=sp.PIPE)
File "/usr/lib64/python2.6/subprocess.py", line 639, in __init__
errread, errwrite)
File "/usr/lib64/python2.6/subprocess.py", line 1228, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory
Then I commented out the subprocess line and used os and it worked immediately. I think I don't fully understand the subprocess module
#!/usr/bin/env python
import sys, os, subprocess as sp
lo = sys.argv[1]
hi = sys.argv[2]
lo = int(lo)
hi = int(hi)
for i in range(lo,hi):
print "i is %d"%i
#p=sp.Popen(['qdel %d'%i],stdout=sp.PIPE)
os.system('qdel %d'%i)
The above code worked flawlessly. I just want to know why and what the advantages are of the subprocess module. Also, I am using a unix shell
If you read manual, you can see that your call to Popen is wrong: you should pass not a single command, but an array of arguments:
p=sp.Popen(['qdel', '%d'%i],stdout=sp.PIPE)
Alternatively, as sc0tt's answer points out, you can use shell=True, but this has some disadvantages in more complex cases: you would have to manually escape all the variable data in the command in case it contains, for example, filenames with spaces or anything much more potentially harmful (like ;)
You want to use shell=True on your Popen call.
p=sp.Popen(['qdel %d'%i], shell=True, stdout=sp.PIPE)
I was also getting same issue. Using shell=True as one of the parameter solved my problem.