1
>>> import subprocess
>>> subprocess.check_output("smartctl -d ata -a /dev/sda", shell=True)
"output of above command prints normally"
>>> subprocess.check_output("smartctl -d ata -a /dev/sdb", shell=True)
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "/usr/lib/python2.7/subprocess.py", line 544, in check_output
       raise CalledProcessError(retcode, cmd, output=output)
subprocess.CalledProcessError: Command 'smartctl -d ata -a /dev/sdb' returned non-zero exit status 64

Can anyone explain to me why the above command with sda works fine but returns an error with sdb? sdc works too, for the record. Also, I am aware of the risk of using shell=True. I am learning python and ran into this problem while writing a test script.

3 Answers 3

2

You can easily see what was wrong with sdb:

try:
    subprocess.check_output("smartctl -d ata -a /dev/sdb", shell=True)
except subprocess.CalledProcessError, e:
    print e.output
Sign up to request clarification or add additional context in comments.

5 Comments

Interestingly, you code gives me the following error: NameError: name 'CalledProcessError' is not defined. edit fixed it to subprocess.CalledProcessError.
Thanks, I've edited my answer. Alternatively you could write from subprocess import CalledProcessError before my piece of code.
When I change to subprocess.CalledProcessError and print e.output, I get the output of the smartctl command with seemingly no errors. Strange, is this somehow expected?
Then nothing can be done from python side: the command really returns nonzero exit status. But googling helped to find the answer: sourceforge.net/p/smartmontools/mailman/message/10780193. "64 (at least, a 1 in the 7th bit) is an indication that there are items in the Error Log"
nit: The modern way to catch exceptions is except SomeException as e rather than except SomeException, e.
1

To know outputs and errors use

import subprocess
c=subprocess.Popen("smartctl -d ata -a /dev/sdb",stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)
output,error=c.communicate()
#now check your error or output

Comments

1

The smartctl command returns the value 64. According to the manual page the return value is a bitfield. Converting 64 to binary yields 01000000, so bit 6 is set (rightmost bit is bit 0). According to the aforementioned manpage:

Bit 6: The device error log contains records of errors.

If you can use Python 3.5, you could use the new high-level API subprocess.run(). This allows you to both capture return value and standard output/error.

prog = ['smartctl',  '-d', 'ata', '-a',  '/dev/sda']
result = subprocess.run(prog, stdout=subprocess.PIPE,
                        stderr=subprocess.PIPE)
if result.returncode == 0:
    print(result.stdout)
else:
   print('smartctl returned error', result.returncode)

1 Comment

Ended up going with the subprocess.Popen option since that better suits my needs. Preferably looking for options compatible with 2.7 and 3.5 but it's gotta work with 2.7. Thanks for the information though

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.