2012-08-19 10 views
8

Sto provando a creare uno script semplice che selezionerà colonne specifiche dal comando unix df - h. Posso usare awk per farlo, ma come possiamo farlo in python?Selezione di colonne specifiche dall'output df -h in python

Ecco df -h uscita:

 
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 

voglio qualcosa di simile:

Colonna 1:

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

Colonna 2:

 
Size 
28G 
814M 
485M 

risposta

10

È possibile utilizzare op.popen per eseguire il comando e recuperare l'output, quindi splitlines e split per dividere le righe e i campi. Eseguire df -Ph anziché df -h in modo che le righe non vengano divise se una colonna è troppo lunga.

df_output_lines = [s.split() for s in os.popen("df -Ph").read().splitlines()] 

Il risultato è un elenco di righe. Per estrarre la prima colonna, è possibile utilizzare [line[0] for line in df_output_lines] (notare che le colonne sono numerate da 0) e così via. È possibile utilizzare df_output_lines[1:] anziché df_output_lines per rimuovere la riga del titolo.

Se si dispone già dell'output di df -h memorizzato in un file, è necessario prima unire le linee.

fixed_df_output = re.sub('\n\s+', ' ', raw_df_output.read()) 
df_output_lines = [s.split() for s in fixed_df_output.splitlines()] 

Si noti che questo non presuppone che né il nome del file system né il punto di montaggio contengano spazi bianchi. Se lo fanno (che è possibile con alcune configurazioni su alcune varianti di Unix), è praticamente impossibile analizzare l'output di df, anche df -P. È possibile utilizzare os.statvfs per ottenere informazioni su un determinato file system (questa è l'interfaccia Python allo C function che le chiamate df internamente per ogni file system), ma non esiste un modo portatile per enumerare i file system.

+0

Oltre a os.statvfs Python 3.3 aggiungerà una nuova funzione [shutil.disk_usage] (http://docs.python.org/dev/library/shutil.html#shutil.disk_usage) che restituisce una tupla denominata con gli attributi total, used e free space. – miles82

+1

Preferire il sottoprocesso anziché os.popen, poiché os.popen è deprecato (http://docs.python.org/library/os#os.popen). – GodMan

+0

Grazie a @Gilles. Ho provato la prima opzione e ha funzionato. Ho dovuto fare così per il modulo di sottoprocesso. ** df_output_lines = [s.split() per s in subprocess.Popen (["df", "-Ph"], stdout = subprocess.PIPE) .communicate() [0] .strip(). splitlines()] ** – user1610085

2

Ecco l'esempio completo:

import subprocess 
import re 

p = subprocess.Popen("df -h", stdout=subprocess.PIPE, shell=True) 
dfdata, _ = p.communicate() 

dfdata = dfdata.replace("Mounted on", "Mounted_on") 

columns = [list() for i in range(10)] 
for line in dfdata.split("\n"): 
    line = re.sub(" +", " ", line) 
    for i,l in enumerate(line.split(" ")): 
     columns[i].append(l) 

print columns[0] 

sua parte dal presupposto che i punti di montaggio non contengono spazi.

Ecco la (soluzione e complicato) più completo che non hard-core numero di colonne:

import subprocess 
import re 

def yield_lines(data): 
    for line in data.split("\n"): 
     yield line 

def line_to_list(line): 
    return re.sub(" +", " ", line).split() 

p = subprocess.Popen("df -h", stdout=subprocess.PIPE, shell=True) 
dfdata, _ = p.communicate() 

dfdata = dfdata.replace("Mounted on", "Mounted_on") 

lines = yield_lines(dfdata) 

headers = line_to_list(lines.next()) 

columns = [list() for i in range(len(headers))] 
for i,h in enumerate(headers): 
    columns[i].append(h) 

for line in lines: 
    for i,l in enumerate(line_to_list(line)): 
     columns[i].append(l) 

print columns[0] 
+0

L'hard-coding delle colonne come 10 non è raccomandato. Dovrebbe essere mantenuto dinamico in modo da assicurarsi che il codice funzioni su vari tipi di linux/unix – GodMan

+0

Hai ragione, ovviamente. Ho assunto che l'autore di domande è un principiante di Python e non ha voluto complicare inutilmente la risposta. Ho aggiunto un codice alternativo che non presuppone il numero di colonne. –

1

Non usando os.popen come è sconsigliato (http://docs.python.org /library/os#os.popen).

Ho messo l'output di df -h in un file: test.txt e solo leggendo da questo file. Ma puoi leggere anche usando il sottoprocesso. Basta supponendo che si è in grado di leggere ogni riga dell'uscita di df -h, il seguente codice potrebbe aiutare: -

f = open('test.txt') 

lines = (line.strip() for line in f.readlines()) 
f.close()  
splittedLines = (line.split() for line in lines) 
listOfColumnData = zip(*splittedLines) 
for eachColumn in listOfColumnData: 
    print eachColumn 

eachColumn mostrerà l'intera colonna che si desidera utilizzare come una lista. Puoi solo iterare su di esso. Se è necessario, posso fornire il codice per leggere l'output da df -h in modo da poter rimuovere la dipendenza da test.txt, ma, se si accede alla documentazione del sottoprocesso, è possibile trovare come farlo facilmente.

0

Questo funziona:

#!/usr/bin/python 

import os, re 

l=[] 
p=os.popen('df -h') 
for line in p.readlines(): 
    l.append(re.split(r'\s{2,}',line.strip())) 


p.close() 

for subl in l: 
    print subl 
+0

Questo non funziona quando otteniamo il seguente risultato: - [['Filesystem', 'Dimensioni', 'Usato Usa usato% montato su'], ['/ 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']] Ci sono 2 problemi in questo codice: - 1. Gli articoli non sono suddivisi correttamente come richiesto, come è evidente in il primo elemento della lista l 2. Dopo aver risolto il problema 1, il requisito dell'utente1610085 è di ottenere i dati in un formato trasposto. L'output fornisce solo tutte le linee divise, ma, non trasposto – GodMan

+0

Potrei risolvere il problema 2 di 'for i in [line [0] per linea in df_output_lines]: ... print i ' – user1610085

2

Non una risposta alla domanda, ma ho cercato di risolvere il problema. :)

from os import statvfs 

with open("/proc/mounts", "r") as mounts: 
    split_mounts = [s.split() for s in mounts.read().splitlines()] 

    print "{0:24} {1:24} {2:16} {3:16} {4:15} {5:13}".format(
      "FS", "Mountpoint", "Blocks", "Blocks Free", "Size", "Free") 
    for p in split_mounts: 
     stat = statvfs(p[1]) 
     block_size = stat.f_bsize 
     blocks_total = stat.f_blocks 
     blocks_free = stat.f_bavail 

     size_mb = float(blocks_total * block_size)/1024/1024 
     free_mb = float(blocks_free * block_size)/1024/1024 

     print "{0:24} {1:24} {2:16} {3:16} {4:10.2f}MiB {5:10.2f}MiB".format(
       p[0], p[1], blocks_total, blocks_free, size_mb, free_mb) 
1

Avevo un punto di montaggio con uno spazio al suo interno. Questo ha gettato via la maggior parte degli esempi. Questo prende in prestito molto da @ZarrHai s' example ma mette il risultato in una dict

#!/usr/bin/python 
import subprocess 
import re 
from pprint import pprint 

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

def yield_lines(data): 
    for line in data.split("\n"): 
     yield line 

def line_to_list(line): 
    pattern = re.compile(r"([\w\/\s\-\_]+)\s+(\w+)\s+([\d\.]+?[GKM]|\d+)" 
          "\s+([\d\.]+[GKM]|\d+)\s+([\d\.]+[GKM]|\d+)\s+" 
          "(\d+%)\s+(.*)") 
    matches = pattern.search(line) 
    if matches: 
     return matches.groups() 
    _line = re.sub(r" +", " ", line).split() 
    return _line 

p = subprocess.Popen(["df", DF_OPTIONS], stdout=subprocess.PIPE) 
dfdata, _ = p.communicate() 

dfdata = dfdata.replace("Mounted on", "Mounted_on") 

lines = yield_lines(dfdata) 

headers = line_to_list(lines.next()) 

columns = [list() for i in range(len(headers))] 
for i,h in enumerate(headers): 
    columns[i].append(h) 

grouped = {} 
for li, line in enumerate(lines): 
    if not line: 
     continue 
    grouped[li] = {} 
    for i,l in enumerate(line_to_list(line)): 
     columns[i].append(l) 
     key = headers[i].lower().replace("%","") 
     grouped[li][key] = l.strip() 

pprint(grouped) 
+0

Puoi aggiungere attribuzione link a quelle risposte da cui hai tratto questo. –

+0

@NathanTuggy Di solito non commento su queste cose. Come daresti l'attribuzione? Un collegamento all'esempio originale? – the7erm

+0

Sì, dovrebbe andare bene. –

0

ho trovato in questo modo più semplice per farlo ...

df -h | awk '{print $1}' 
Problemi correlati