python - subprocess' check_output - return shell message - python

Here is my code:
from subprocess import check_output
print check_output('whoami', shell=True)
This works fine.
However, if I put a command that isnt' existent it will say:
raise CalledProcessError(retcode, cmd, output=output)
CalledProcessError: Command 'test' returned non-zero exit status 1
When if you were to run this on your shell, it would say something like:
'test' isnot recognized as an intenral or external command, operable program or batch file.
How can I get this instead?

As you can read in the subprocess.check_output documentation:
If the return code was non-zero it raises a CalledProcessError. The CalledProcessError object will have the return code in the returncode attribute and any output in the output attribute.
So you can do this:
import subprocess
try:
print subprocess.check_output('test', shell=True)
except subprocess.CalledProcessError, e:
print e.output

Related

subprocess.CalledProcessError: returned non-zero exit status 1, while os.system does not raise any error

Given the following command:
newman run tests.postman_collection.json -e environment.json --reporters testrail,json,html
Raises:
RuntimeError: command 'newman run tests.postman_collection.json -e environment.json --reporters testrail,json,html
' return with error (code 1): b'\nhttps://host.testrail.io/index.php?/runs/view/1234\n'
Py code that executes the command:
try:
newmanCLI_output = subprocess.check_output(npmCLi, shell=True).decode().strip()
except subprocess.CalledProcessError as e:
raise RuntimeError("command '{}' return with error (code {}): {}".format(e.cmd, e.returncode, e.output))
And yes I do use the check_output return.
The output is a url to test rail reports
That's a misfeature of os.system; it returns the exit code so you can examine it, but doesn't raise an error if something fails.
The check in subprocess.check_output means check that the command succeeded, or raise an exception otherwise. This is generally a good thing, as you don't want processes to die underneath you without a warning.
But you can work around it with subprocess.run if you want to disable it;
import shlex
result = subprocess.run(shlex.split(npmCLi), text=True, capture_output=True)
newmanCLI_output = result.stdout
The switch to avoid shell=True and use shlex.split to parse the string instead is not crucial, but hopefully demonstrates how to do these things properly.
You should still understand why exactly your command fails, and whether it is safe to ignore the failure.

How to capture return code for subprocess.check_call in Python

I have a script that is executing 5 different shell commands and I'm using subprocess.check_call() to execute them. The problem is that I can't seem to figure out how to properly capture and analyze the return code.
According to the docs The CalledProcessError object will have the return code in the returncode attribute., but I don't understand how to access that. If I say
rc = subprocess.check_call("command that fails")
print(rc)
It tells me
subprocess.CalledProcessError: Command 'command that fails' returned non-zero exit status 1
But I can't figure out how to capture just the integer output of 1.
I'd imagine this must be doable somehow?
With check_call you'll have to add a try/except block and access the exception. With subprocess.run you can access the result without a try/except block.
import subprocess
try:
subprocess.check_call(["command", "that", "fails"])
except subprocess.CalledProcessError as e:
print(e.returncode)
Or using subprocess.run:
result = subprocess.run(["command", "that", "fails"])
print(result.returncode)
Whenever the subprocess.check_call method fails is raises a CalledProcessError. From the docs:
subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False, cwd=None, timeout=None, **other_popen_kwargs)
Run command with arguments. Wait for command to complete. If the
return code was zero then return, otherwise raise CalledProcessError.
The CalledProcessError object will have the return code in the
returncode attribute.
You may just want subprocess.run or to use a try/except block to handle the CalledProcessError
perhaps
rc = subprocess.run("some_cmd").returncode
or
try
...
rc = subprocess.check_call("command that fails")
except CalledProcessError as error:
rc = error.returncode

check_output doesn't works in python 3.6 while subprocess works fine

i am trying to get the output of a command in my python program by using "check_output" method. but i'm getting this error:
out = check_output(command5 , shell=True)
File "/usr/lib64/python3.6/subprocess.py", line 336, in check_output
**kwargs).stdout
File "/usr/lib64/python3.6/subprocess.py", line 418, in run
output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command 'oscap xccdf eval --profile xccdf_org.ssgproject.content_profile_rht-ccp --results-arf arf.xml /usr/share/xml/scap/ssg/content/ssg-centos7-ds.xml' returned non-zero exit status 2.
this is the part of my program that is related:
command4 = "oscap xccdf eval --profile xccdf_org.ssgproject.content_profile_rht-ccp --results-arf arf.xml /usr/share/xml/scap/ssg/content/ssg-centos7-ds.xml"
out = check_output(command4 , shell=True)
I am sure that the command is alright because I get the results when I write:
subprocess.call(command5,shell=True)
I am using python 3.6, and work in centos 7.
any idea why the check_output can not get the result?
This is entirely normal, because the command you ran produced a non-zero exit code. It means that the command you ran is signalling that something may be wrong.
See the subprocess.check_output() documentation:
If the return code was non-zero it raises a CalledProcessError.
and
This is equivalent to:
run(..., check=True, stdout=PIPE).stdout
where the check=True flag tells run() to raise an exception when return_value is not 0:
If check is true, and the process exits with a non-zero exit code, a CalledProcessError exception will be raised.
The other function you used, subprocess.call(), does not set check=True:
Run the command described by args. Wait for command to complete, then return the returncode attribute.
This is equivalent to:
run(...).returncode
So either don't use check_output(), or catch the exception thrown, or fix the command you are running. That call() worked is no indication that the process actually produced a successful result.
For example, you could use subprocess.run() directly:
proc = subprocess.run(
command5, shell=True, text=True
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if proc.returncode:
print(f'Issue reported, exit code {proc.returncode}, stderr:')
print(proc.stderr)
else:
print(proc.stdout)

Python: catch git error

I'm trying to catch a very simple error, but with no result for now.
I've created a tag on my Git repository and trying to catch an error with the creation of existing tag. My code looks like:
try:
check_call(['git', 'tag', '-a', '1.2.3', '-m', 'test tag.'])
except CalledProcessError as err:
print err.output, err.returncode, err.message
I can't catch a message: tag '1.2.3' already exists.
It raises in my git command, but I can't catch it.
I was also trying to replace check_call with check_output, but it also doesn't help.
Using just a returncode is not enough for me, because it raises 128 for this case and many others (I want to have separate handling for different issues).
Ideas?
You need to use check_output() to get the output. The reason you do not get that working, is because the error message is not written to stdout but to stderr. This can easily be taken care of by redirecting stderrto stdout. Using the following should work for you:
from subprocess import check_output, STDOUT, CalledProcessError
try:
check_output(['git', 'tag', '-a', '1.2.3', '-m', 'test tag.'], stderr=STDOUT)
except CalledProcessError as err:
print err.output, err.returncode, err.message
Here you can see that I have used check_output() and redirected stderr .
Rewriting the answer.
import subprocess
command = ['git', 'tag', '-a', '1.2.3', '-m', 'test tag.']
p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output = p.stdout.read()
p.communicate()
if p.returncode == 0:
handleSuccess() # supposed you have such a function
else:
# you can handle any error based on the output of git
if 'tag' in output and 'already exists' in output:
handleTagAlreadyExistsError() # supposed you have such a function

subprocess python - non zero exception

I would like to run the subprocess.check_output method for my python script.
try:
logger.info('Loading URL ' + line)
wp_output = subprocess.checkout(['ruby', PATH + '/wpscan.rb', '--url', line, '--enumerate',
'vp', '--enumerate', 'vt'])
print wp_output
logger.info(wp_output)
return wp_output.strip()
except KeyboardInterrupt:
raise
except subprocess.CalledProcessError, e:
logger.exception('ERROR - Problem occurred while using wpscan.')
the exception:
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 573, in check_output
raise CalledProcessError(retcode, cmd, output=output)
CalledProcessError: Command '[u'ruby', u'./wpscan/wpscan.rb', u'--url', 'www.website.de', u'--enumerate', u'vp', u'--enumerate', u'vt']' returned non-zero exit status 1
if I run check_output I get a non-zero exception, if I use only "subprocess.call" I get as result "print wp_output" only the int 1??
What I am doing wrong? I would like to get the output as a string (wp_output).
When you run subprocess.call is returns an int that represents the exit code of the program. Typically a 0 means everything ran fine, and other numbers, such as your 1, indicate an error.
subprocess.check_output will specifically treat an error as an exception within python itself, and raise it, which leads to your result.
If you want the string output whether it was an error or a success, use Popen.
command = ['ruby', PATH + '/wpscan.rb', '--url', line, '--enumerate',
'vp', '--enumerate', 'vt']
wp_output = subprocess.Popen(command, stdout=subprocess.PIPE)
wp_output = wp_output.communicate()
print wp_output
Using Popen with subprocess.PIPE and then running communicate on it will gives you a tuple containing the text that your command returned, whether it's an error or not.
This is an addon to SuperBiasedMan's comment. It will be nice to redirect the stderr too as errors usually appear in stderr than stdout.
command = ['ruby', PATH + '/wpscan.rb', '--url', line, '--enumerate',
'vp', '--enumerate', 'vt']
wp_proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
wp_output, wp_error = wp_proc.communicate()
if wp_error != '':
print wp_error
else:
print wp_output

Categories

Resources