Konstantin Monahov
Konstantin Monahov

Reputation: 173

Python subprocess.CalledProcessError: returned non-zero exit status 2

#!/usr/bin/env python
# encoding: utf-8

import re
import subprocess
import time
import json


def get_temperatures(disks):
    sensors = subprocess.check_output(["sensors"])
    temperatures = {match[0]: float(match[1]) for match in re.findall("^(.*?)\:\s+\+?(.*?)°C", 
                                            sensors, re.MULTILINE)}
    for disk in disks:
        output = subprocess.check_output(["smartctl", "-A", disk])
        temperatures[disk] = int(re.search("Temperature.*\s(\d+)\s*(?:\([\d\s]*\)|)$", 
                                            output, re.MULTILINE).group(1))
    return temperatures


def main():
    while True:
        print json.dumps(get_temperatures(("/dev/sda2", "/dev/sdb1")))
        time.sleep(20)


if __name__ == '__main__':
    main()

This is small script to monitor temperatures in Python, using smartmontools and lm-sensors. But when i try to run it i have a error

subprocess.CalledProcessError: Command '['smartctl', '-A', '/dev/sda2']' returned non-zero exit status 2

But when i try this command manually in terminal they work great.

Some info:

uname -a 
Linux LME 4.0.0-040000-generic #201504121935 SMP Sun Apr 12 23:36:33 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

Upvotes: 15

Views: 80529

Answers (2)

BlackVegetable
BlackVegetable

Reputation: 13034

A CalledProcessError will be raised if any non-zero exit code is returned by your called process. On the command line, you should echo $? to get the last return code and see if it really does return 2. I suspect it will.

If that is okay in your python code, you can except the CalledProcessError and get any information from within its attributes especially the output attribute. (Look up this error in the python docs for more information.)

Example:

import subprocess
output = None
try:
    output = subprocess.check_output(["smartctl", "-A", "/dev/sda2"])
except subprocess.CalledProcessError as e:
    output = e.output

Upvotes: 13

Eric Renouf
Eric Renouf

Reputation: 14500

Return code of 2 from smartctl means it failed to open the device. Make sure that the user who is running the Python code has permission to open all of the disks you want it to check.

From the RETURN VALUES section of smartctl's man page:

Bit 1: Device open failed, or device did not return an IDENTIFY DEVICE structure

So I suspect this is really a permissions problem. I verified this on my system. If I run subprocess.check_output( [ 'smartctl', '-A', '/dev/sda2' ] ) I get the error with it returning 2, but if I run subprocess.check_output( [ 'sudo', 'smartctl', '-A', '/dev/sda2' ] ) it works and I see the output of the command.

Upvotes: 5

Related Questions