Selecting specific columns from df -h output in python

Viewed 11201

I'm trying to create a simple script that will select specific columns from the unix df - h command. I can use awk to do this but how can we do this in python?

Here is df -h output:

Filesystem                    Size  Used  Avail  Use%  Mounted on
/dev/mapper/vg_base-lv_root   28G   4.8G    22G   19%  /
tmpfs                        814M   176K   814M    1%  /dev/shm
/dev/sda1                    485M   120M   340M   27%  /boot

I want something like:

Column 1:

Filesystem
/dev/mapper/vg_base-lv_root           
tmpfs                 
/dev/sda1

Column 2:

Size
28G
814M 
485M   
8 Answers

One thing I've noticed in all systems I've access to: df with option -P prints in whitespace aligned columns. This means that the headers are the same width (padded with whitespace) as the rest of the items. Building on the7erm's answer, this uses the size of the header to ensure that it gets the whole mount point, even if there is a space in it.

This has been tested on Ubuntu 14.04, 16.04, and FreeBSD 9.2.

I've solved this two different ways, the first is a direct answer to the OP's question, giving 6 columns, each of which starts with the header, and then has each mountpoint in order below it:

import pprint
import subprocess
import re

DF_OPTIONS = "-PlaTh" # remove h if you want bytes.

# Get the entire output of df
dfdata = subprocess.getoutput("df " + DF_OPTIONS)

# Split it based on newlines
lines = dfdata.split("\n")

dfout = {}
headers = []

# Grab the headers, retain whitespace!
# df formats in such a way that each column header has trailing whitespace 
# so the header is equal to the maximum column width. We want to retain
# this for len()
headersplit = re.split(r'(\s+)', lines[0].replace("Mounted on","Mounted_on "))
headers = [i+j for i,j in zip(headersplit[0::2],headersplit[1::2])]

for hi,head in enumerate(headers):
  dfout[hi] = [head.strip()]

for line in lines[1:]:
  pos = 0
  dfstruct = {}
  for hi,head in enumerate(headers):
    # For the last item, grab the rest of the line
    if head == headers[-1]:
      item = line[pos:]
    else:
      # Get the current item
      item = line[pos:pos+len(head)]

    pos = pos + len(head)

    #Strip whitespace and add it to the list

    dfstruct[head.strip()] = item.strip()
    dfout[hi].append(item.strip())

pprint.pprint(dfout)

The second is more useful to me, and the solution to why I stumbled upon this question in the first place. This puts the information into an array of dicts:

import pprint
import subprocess
import re

DF_OPTIONS = "-PlaTh" # remove h if you want bytes.

# Get the entire output of df
dfdata = subprocess.getoutput("df " + DF_OPTIONS)

# Split it based on newlines
lines = dfdata.split("\n")

dfout = []
headers = []

# Grab the headers, retain whitespace!
# df formats in such a way that each column header has trailing whitespace 
# so the header is equal to the maximum column width. We want to retain
# this for len()
headersplit = re.split(r'(\s+)', lines[0].replace("Mounted on","Mounted_on "))
headers = [i+j for i,j in zip(headersplit[0::2],headersplit[1::2])]

for line in lines[1:]:
  pos = 0
  dfstruct = {}
  for head in headers:
    # For the last item, grab the rest of the line
    if head == headers[-1]:
      item = line[pos:]
    else:
      # Get the current item
      item = line[pos:pos+len(head)]

    pos = pos + len(head)
    #Strip whitespace for our own structure
    dfstruct[head.strip()] = item.strip()

  dfout.append(dfstruct)

pprint.pprint(dfout)
Related