How to Parse /etc/os-release

The Problem

As part of my daily tasks, I need to parse the /etc/os-release file for information using Python. I have seen various attempts from other people, most of which are too complicated, too cumbersome, so I came up with my own.

Below is a sample contents.

NAME="Ubuntu"
VERSION="20.04.3 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.3 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal

The Solution

The easiest way to parse this file is to you the PyYAML library. However, in some projects, my team does not have access to third-party libraries and have to stay within the Python 3.7's standard libraries.

After several attempts, I came up with a fairly easy solution: Use the csv library. Below is a code snippet which parses /etc/os-release and returns a dictionary.

import csv
import pathlib
from pprint import pprint

path = pathlib.Path("/etc/os-release")
with open(path) as stream:
    reader = csv.reader(stream, delimiter="=")
    os_release = dict(reader)

pprint(os_release)

Here is the output:

{'BUG_REPORT_URL': 'https://bugs.launchpad.net/ubuntu/',
 'HOME_URL': 'https://www.ubuntu.com/',
 'ID': 'ubuntu',
 'ID_LIKE': 'debian',
 'NAME': 'Ubuntu',
 'PRETTY_NAME': 'Ubuntu 20.04.3 LTS',
 'PRIVACY_POLICY_URL': 'https://www.ubuntu.com/legal/terms-and-policies/privacy-policy',
 'SUPPORT_URL': 'https://help.ubuntu.com/',
 'UBUNTU_CODENAME': 'focal',
 'VERSION': '20.04.3 LTS (Focal Fossa)',
 'VERSION_CODENAME': 'focal',
 'VERSION_ID': '20.04'}

How it Works

  • The file contains lines of key=value, so I use the csv library to read it and specify the equal sign as fields delimiters.
  • The reader will yield a list of (key, value) tuples
  • The dict built-in turns that list of tuples into a dictionary

Conclusion

After several attempts, I like this solution the best because it leaves the parsing to a standard library, which I assume well tested.

45