Pe parcursul laboratoarelor, vom dori sa agregam si sa sumarizam rezultatele rularii scripturilor de ns-3 sub forma unor grafice, urmand ca apoi sa interpretam aceste grafice.
In general, workflow-ul unui laborator va arata astfel:
Rularea succesiva cu argumente variabile/dinamice va putea fi automatizata prin intermediul unui script Bash
. In mod ideal, acest script ar trebui sa salveze datele de interes intr-un fisier (.CSV preferabil) pentru a putea fi folosit ulterior pentru a obtine grafice.
Pentru realizarea graficelor, ne vom folosi de limbajul Python, de modulul de Python
matplotlib si de pachetul Jupyter Notebook pentru o vizualizare mai usoara a graficelor. Jupyter Notebook
este o aplicatie care porneste un server web local si care permite rularea de cod (Python
, Java
, etc) in cadrul unei pagini web locale care poarta numele de notebook
.
Pentru a lansa aplicatia de Jupyter Notebook, rulati urmatoarea comanda:
student@isrm-vm-2020:~$ jupyter-notebook
Aceasta comanda va porni serverul web care sta in spatele aplicatiei. Pentru a putea accesa pagina de baza a serverului web in browser, exista doua variante:
To access the notebook, open this file in a browser: file:///home/student/.local/share/jupyter/runtime/nbserver-5314-open.html Or copy and paste one of these URLs: http://localhost:8888/?token=ca54fe5b73bc1eb1f51f2f209e99eabb69117fd73664b721
Odata intrati pe pagina web, putem trece la crearea unui notebook (butonul New → Python3)
In cadrul laboratoarelor de ISRM, vom folosi MS Teams assignments pentru a urca rezolvarile exercitiilor, pentru a primi feedback pe rezolvari/interpretari si pentru a primi nota pe laborator.
Fisierele de interes care vor trebui urcate in MS Teams incepand cu al doilea laborator sunt urmatoarele:
La început, vom analiza un fișier de date. Acesta poate fi un fișier text care conține datele ca coloane. Descarcati fișierul de date numit plotting_data1.csv ce conține:
# comentarii # X Y 1 2 2 3 3 2 4 1
Pe baza acestor date, graficul poate fi construit folosind urmatorul template (pe care il puteti folosi si la restul laboratoarelor):
import copy import numpy as np import matplotlib import matplotlib.pyplot as plt # Calea absoluta catre fisierul de date din care citim # TODO - trebuie inlocuita cu calea corecta DATA_FILE = '/home/student/plotting_data1.csv' columns = ['x', 'y'] # Citim datele din fisier # Argumentul delimiter precizeaza care este delimitatorul dintre coloane # Argumentul skip_header precizeaza cate linii nu vor fi citite pornind cu inceputul fisierului # Argumentul names este unul foarte util deoarece permite asocierea de nume pentru coloanele din fisier si # de asemenea duce la un acces foarte usor al datelor in script. In acest exemplu, names va fi egal cu ['x', 'y'] # ceea ce inseamna ca putem accesa valorile din prima coloana prin sim_data['x']. # Argumentul dtype setat specifica modul in care vor fi interpretate coloanele (string-urile ca string-uri, float-urile ca float-uri). # In absenta acestui argument, valorile din coloane vor fi interpretate ca float. sim_data = np.genfromtxt(DATA_FILE, delimiter=' ', skip_header=2, names=columns, dtype=None) def plot_data(sim_data): data = copy.deepcopy(sim_data) # Apelul subplots poate fi folosit pentru a crea mai multe subgrafice in cadrul aceluiasi grafic sau in cadrul unor grafice diferite # Prin figsize se specifica dimensiunea graficului fig, ax = plt.subplots(figsize=(12,12)) # Valori stilistice pentru grafic ax.grid(color='b', alpha=0.5, linestyle='dashed', linewidth=0.5) # Denumirile axelor Ox si Oy, precum si titlul graficului plt.xlabel('X values') plt.ylabel('Y values') plt.title('A very nice looking plot') # Aici este construit efectiv graficul. Campul label va fi folosit in cadrul legendei graficului ax.plot(data['x'], data['y'], label='My plot') ax.legend() plt.show() if __name__ == '__main__': plot_data(sim_data)
Introduceti acest snippet code in notebook cu mentiunea de a corecta calea data de variabila DATA_FILE. In urma rularii codului in notebook (butonul Run), imaginea rezultată este:
Pentru a include mai multe subgrafice in cadrul aceluiasi grafic, este suficient sa apelam ax.plot
pentru fiecare subgrafic nou:
import copy import numpy as np import matplotlib import matplotlib.pyplot as plt # Calea absoluta catre fisierul de date din care citim # TODO - trebuie inlocuita cu calea corecta DATA_FILE = '/home/student/plotting_data1.csv' columns = ['x', 'y'] # Citim datele din fisier # Argumentul delimiter precizeaza care este delimitatorul dintre coloane # Argumentul skip_header precizeaza cate linii nu vor fi citite pornind cu inceputul fisierului # Argumentul names este unul foarte util deoarece permite asocierea de nume pentru coloanele din fisier si # de asemenea duce la un acces foarte usor al datelor in script. In acest exemplu, names va fi egal cu ['x', 'y'] # ceea ce inseamna ca putem accesa valorile din prima coloana prin sim_data['x']. # Argumentul dtype setat specifica modul in care vor fi interpretate coloanele (string-urile ca string-uri, float-urile ca float-uri). # In absenta acestui argument, valorile din coloane vor fi interpretate ca float. sim_data = np.genfromtxt(DATA_FILE, delimiter=' ', skip_header=2, names=columns, dtype=None) def plot_data(sim_data): data = copy.deepcopy(sim_data) # Apelul subplots poate fi folosit pentru a crea mai multe subgrafice in cadrul aceluiasi grafic sau in cadrul unor grafice diferite # Prin figsize se specifica dimensiunea graficului fig, ax = plt.subplots(figsize=(12,12)) # Valori stilistice pentru grafic ax.grid(color='b', alpha=0.5, linestyle='dashed', linewidth=0.5) # Denumirile axelor Ox si Oy, precum si titlul graficului plt.xlabel('X values') plt.ylabel('Y values') plt.title('A very nice looking plot') # Aici este construit efectiv graficul. Campul label va fi folosit in cadrul legendei graficului ax.plot(data['x'], data['y'], label='My plot') ax.plot(data['y'], data['x'], label='My secondary plot') ax.legend() plt.show() if __name__ == '__main__': plot_data(sim_data)
O necesitate frecventă este reprezentarea datelor cu bare de erori pentru a indica de exemplu comportarea funcției într-un punct. În următorul exemplu avem măsurători ale puterii pentru o rezistență dată, stocate în formatul: r, P, Perror care poate semnifica eroarea de măsurare a puterii:
# X Y stddev 50.000000 0.036990 0.007039 47.000000 0.036990 0.007039 44.000000 0.038360 0.007053 41.000000 0.042160 0.007050 38.000000 0.043200 0.007018 35.000000 0.046900 0.007021 32.000000 0.048840 0.006963 29.000000 0.052000 0.006929 26.000000 0.055470 0.006947 23.000000 0.060000 0.006882 20.000000 0.064660 0.006879 17.000000 0.069600 0.006936 14.000000 0.079800 0.007080 11.000000 0.086920 0.007232 8.000000 0.085500 0.007262 5.000000 0.101260 0.008415 2.000000 0.091000 0.011203 0.000000 0.081480 0.011828
Vom plota astfel:
import copy import numpy as np import matplotlib import matplotlib.pyplot as plt # Calea absoluta catre fisierul de date din care citim # TODO - trebuie inlocuita cu calea corecta DATA_FILE = '/home/student/battery.dat' columns = ['resistance', 'power', 'power_error'] # Citim datele din fisier sim_data = np.genfromtxt(DATA_FILE, delimiter=' ', skip_header=2, names=columns, dtype=None) def plot_data(sim_data): data = copy.deepcopy(sim_data) fig, ax = plt.subplots(figsize=(12,12)) ax.grid(color='b', alpha=0.5, linestyle='dashed', linewidth=0.5) plt.xlabel('X values') plt.ylabel('Y values') plt.title('A very nice looking plot') ax.errorbar(data['resistance'], [1000 * x for x in data['power']], yerr=[1000 * x for x in data['power_error']], fmt='-o', label='My plot') ax.legend() plt.show() if __name__ == '__main__': plot_data(sim_data)
Valorile puterii sunt stocate în Watt în fișierul de date, dar au valori mai mici decât 1. De aceea dorim să folosim mW ca unitate de măsură.
Pentru a extrage primele sau ultimele linii dintr-un output mare folosim head
și tail
:
student@isrm-vm:~$ dmesg | head -n 20 student@isrm-vm:~$ dmesg | tail -n 50
Putem extrage folosind sed
explicit anumite linii. De exemplu din fișierul students.csv vrem liniile 10-16:
student@isrm-vm:~$ cat students.csv | sed -n '10,16p;17q'
Putem extrage informații structurate pe linii și coloane folosind utilitarul cut:
student@isrm-vm:~$ cat /etc/passwd | cut -d':' -f1,6 | head -3 root:/root daemon:/usr/sbin bin:/bin
Utilitarul awk permite aceleași acțiuni ca și cut, dar funcționalitatea sa este mai extinsă. Spre exemplu, awk poate folosi o expresie regulată ca delimitator, pe când cut acceptă un singur caracter:
student@isrm-vm:~$ netstat -i Kernel Interface table Iface MTU Met RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg eth0 1500 0 1955 0 0 0 521 0 0 0 BMRU lo 65536 0 359 0 0 0 359 0 0 0 LRU student@isrm-vm:~$ netstat -i | cut -d' ' -f1,2 Kernel Interface Iface eth0 lo student@isrm-vm:~$ netstat -i | awk -F' *' '{print $1,$2,$4}' Kernel Interface Iface MTU RX-OK eth0 1500 2029 lo 65536 359
Awk este considerat un fel de limbaj de programare ce vizează procesarea text.
Există script-uri awk complexe ce se aseamănă programelor C.
Printre altele, awk permite implementarea și apelarea de funcții. AWK (K vine de la Kernighan) este mic, simplu, și rapid, spre deosebire de perl sau python. Nu poți face tot ce faci în perl/python, dar poți face foarte ușor multe taskuri de procesare de text. Are o sintaxă apropiată de C, dar preferă datele organizate pe coloane, ca foarte multe date în rețelistică: trace-uri de simulare, tcpdump, loguri, etc. Un mare avantaj este ca poate fi rulat direct de pe linia de comandă,
fără a mai folosi un script separat - de multe ori apare într-un pipeline cu cat, sed, tr
.
cat trace.out | awk '{print $2}'
afișează coloana a doua a fiecărei linii. De exemplu, pentru acest fișier:
10 2 0.2 11 3 0.3 12 2 0.2 13 3 0.1 14 4 0.05
cat trace.out | awk '{print $1+$2, $2 $3, i++;}'
produce
12 20.2 0 14 30.3 1 14 20.2 2 0 3 16 30.1 4 18 40.05 5
$
trebuie protejat de shell cat trace.out | awk 'NF==3 { s+=$3; n++} /1[2-3]/{print $0} END{print n, s/n}'
produce
12 2 0.2 13 3 0.1 5 0.17
$0
= toată linia #!/bin/bash T1="foo" T2="bar" if [ "$T1" = "$T2" ]; then echo expression evaluated as true else echo expression evaluated as false fi
Script pentru a afișa doar studenții care au media > 5 din acest fisier students.csv
#!/bin/bash IFS=',' while read name group final_grade test_grade practical_grade; do if test "$final_grade" -gt 5; then echo "$name,$group,$final_grade" fi done < students.csv
Pașii de mai sus puteau fi realizați și cu ajutorul comenzii cut
. Dar, în cazul parsării folosind construcția while read
avem două avantaje:
cut
permitea afișarea de coloane doar în ordinea din fișierul de intrare;while read
informația parsată. Spre exemplu, afișarea poate avea forma "Studentul ... face parte din grupa ...".
În bash există și construcții de tipul for
. Un exemplu comun este acela de a itera prin conținutul unui
director și de a face prelucrări asupra fișierelor.
Spre exemplu, dorim să facem backup tuturor fișierelor dintr-un director trimis ca parametru în script:
#!/bin/bash for file in $1/* do if test -f $file; then stat --print="%a %F %n\n" $file cp $file $file.bkp fi done
Se poate itera și pe output-ul unei comenzi:
#!/bin/bash cd ~ unzip media.zip cd media for file in $(find . -iname '*.jpg') do echo $file done
Bash face toate calculele pe integer, deci nu poate fi folosit pentru a calcula medii (mean, median, standard deviation).
$ x=5; echo $(($x / 3)) 1
$ x=24 $ y=25 $ b=`expr $x = $y` # Test equality. $ echo "b = $b" # 0 ( $x -ne $y ) b = 0
Putem folosi utilitarul bc
cu pipe pentru calcule în floating point:
$ echo '6.5 / 2.7' | bc 2 $ echo 'scale=3; 6.5/2.7' | bc 2.407
$ awc() { awk "BEGIN{print $*}"; } $ for i in `seq 1 1 4`; do awc "$i + sqrt($i)"; done 2 3.41421 4.73205 6
Majoritatea graficelor pe care dorim sa le plotăm se folosesc de același script de simulare pe care îl rulăm cu parametri diferiți, iar la final recoltăm din outputul lui una sau mai multe valori. Dacă simularea nu folosește resurse temporare care pot duce la race conditions, se poate rula în paralel pentru a putea folosi core-urile existente. Utilitarul GNU parallel
este potrivit pentru acest job, întrucât detectează automat numărul de core-uri, și are multe opțiuni pentru scriptare (nu toate naturale).
Exemple simple:
$ parallel echo "{1} a{2}" ::: $(seq 1 1 3) ::: $(seq 100 102) 1 a100 1 a101 1 a102 2 a100 2 a101 2 a102 3 a100 3 a101 3 a102
Un gotcha este rularea mai multor comenzi shell care este posibilă doar prin înglobarea lor într-o funcție sau script separat:
$ cat > batch sleep $1 echo $2 $ parallel ./batch ::: $(seq 3 -1 1) ::: $(seq 100 102) 100 100 101 102 100 101 101 102 102
Un altul este afișarea rezultatelor taskurilor în ordine secvențială, nu atunci când se termină fiecare:
$ parallel -k bash ./batch ::: $(seq 3 -1 1) ::: $(seq 100 102) 100 101 102 100 101 102 100 101 102
Exemplu care poate fi adesea refolosit în acest semestru:
$ function run_fixed(){ echo -n "$1 $2 " ./waf --run "lab6-7-cw --payloadSize=212 --ns=$1 --nd=$1 --minCw=$2 --maxCw=$2 --pcap=false" | tail -n1 } $ export -f run_fixed $ parallel -k run_fixed {1} {2} ::: 4 6 7 20 40 ::: 3 7 15 31 63 127 255 511 1023 2047 4095
Acest exemplu rulează scriptul ns3 pentru toate combinațiile de parametri minCw si maxCw listate în secventele separate de ::: Opțiunea -k asigură afișarea rezultatelor în ordine, chiar dacă în realitate se rulează în paralel pe mai multe core-uri, si unele taskuri se termină mai repede.
Vom folosi fișierele de aici: https://github.com/systems-cs-pub-ro/uso/tree/master/lab09/draw-plots
De multe ori, una dintre cele mai bune forme de prezentare a datelor e în forma unor grafice. Există mai multe tipuri de grafice (cu puncte, cu linii, pie chart, bar chart etc.) decizia de a folosi un tip sau altul aparținând observatorului uman.
Pentru trasarea de grafice, putem folosi utilitarul gnuplot. Gnuplot primește comenzi care pot fi trecute într-un script pentru a trasa grafice.
Pentru un exemplu de utilizare a gnuplot, accesăm subdirectorul draw-plots/
din directorul laboratorului:
student@mjolnir:~/uso.git/lab11/process-table-data$ cd ../draw-plots/ student@mjolnir:~/uso.git/lab11/draw-plots$ ls draw-overhead-for-kpps.gnu transcode-overhead-for-kpps.csv memwalk-overhead-for-kpps.csv
În acest director sunt două fișiere format CSV care conțin rezultatele unor experimente ce folosesc trafic de rețea. Fișierele memwalk-overhead-for-kpps.csv
și transcode-overhead-for-kpps.csv
conțin overhead-ul în secunde pentru diverse viteze de trafic de rețea, măsurate în kilopackets per second (kpps). Prima coloană din fiecare fișier reprezintă viteza în kpps
, iar a doua coloană overhead-ul în secunde. Cele două fișiere indică overhead-ul indus în momentul rulării unor aplicații numite respectiv memwalk
și transcode
.
Tot aici se găsește și un script gnuplot, draw-overhead-for-kpps.gnu
care trasează graficul dependenței overhead-ului față de viteza de trafic pentru aplicația memwalk
.
Pentru a rula scriptul folosim comanda
student@mjolnir:~/uso/lab09/draw-plots$ gnuplot draw-overhead-for-kpps.gnu
În urma rulării rezultă fișierul overhead-for-kpps.pdf
:
student@mjolnir:~/uso/lab09/draw-plots$ ls draw-overhead-for-kpps.gnu overhead-for-kpps.pdf memwalk-overhead-for-kpps.csv transcode-overhead-for-kpps.csv
Putem vizualiza fișierul cu ajutorul utilitarului evince
folosind comanda
student@mjolnir:~/uso/lab09/draw-plots$ evince overhead-for-kpps.pdf
Întrucât dorim să plasăm pe același grafic și datele pentru aplicația transcode
, vom adăuga în script și fișierul de intrare transcode-overhead-for-kpps.csv
. Pentru aceasta vom schimba ultima linie din script în două linii care vor avea conținutul
plot 'memwalk-overhead-for-kpps.csv' with linespoints, \ 'transcode-overhead-for-kpps.csv' with linespoints
După ce schimbăm ultima linie din fișier conform indicațiilor de mai sus și după ce salvăm fișierul, rulăm din nou scriptul și deschidem fișierul rezultat overhead-for-kpps.pdf
:
student@mjolnir:~/uso/lab09/draw-plots$ gnuplot draw-overhead-for-kpps.gnu student@mjolnir:~/uso/lab09/draw-plots$ evince overhead-for-kpps.pdf
Observăm că nu avem legendă și nu ne putem da ușor seama care grafic reprezintă care aplicație. În scriptul draw-overhead-for-kpps.gnu
am dezactivat legenda prin folosirea liniei
unset key
Pentru a activa legenda comentăm acea linie în cadrul scriptului prefixând-o cu simbolul diez (#
, hash):
#unset key
După ce am comentat linia care dezactiva legenda, rulăm din nou scriptul și deschidem fișierul rezultat overhead-for-kpps
:
student@mjolnir:~/uso/lab09/draw-plots$ gnuplot draw-overhead-for-kpps.gnu student@mjolnir:~/uso/lab09/draw-plots$ evince overhead-for-kpps.pdf
Acum legenda apare pe grafic, dar este plasată neconvenabil în partea de sus a ecranului. Cel mai bine este ca legenda să fie plasată în partea dreapta centru. Pentru aceasta scriem în fișier linia
set key right center
Putem scrie linia oriunde înainte de linia plot
. O putem scrie imediat după linia comentată mai sus. După ce am adăugat linia care poziționează legenda în partea dreapta centru, rulăm din nou scriptul și deschidem fișierul rezultat overhead-for-kpps
:
student@mjolnir:~/uso/lab09/draw-plots$ gnuplot draw-overhead-for-kpps.gnu student@mjolnir:~/uso/lab09/draw-plots$ evince overhead-for-kpps.pdf
Ca ultimă schimbare, putem configura graficul să folosească pe post de limite pentru ordonată (axa Oy
) reprezentând overhead-ul, valorile 0
și 150
. Pentru aceasta adăugăm în script linia
set yrange [0:150]
Putem scrie linia oriunde înainte de linia plot
.
Pentru estetică, putem să precizăm etichetelor din legendă. Pentru aceasta înlocuim liniile care defineau graficul (ultimele două linii din script) cu liniile de mai jos, care folosesc cuvântul cheie title
pentru a preciza etichetele în legendă:
plot 'memwalk-overhead-for-kpps.csv' with linespoints title 'memwalk', \ 'transcode-overhead-for-kpps.csv' with linespoints title 'transcode'
Apoi rulăm din nou scriptul și deschidem fișierul rezultat. Rezultatul final trebuie să fie similar imaginii de mai jos.
În acest moment avem un grafic care indică dependența overhead-ului de viteza traficului pentru două aplicații. Datele au fost prelucrate din două fișiere de intrare în format CSV, conținând două coloane: prima cu viteza traficulului (în kilopackets per second) și a doua cu overhead-ul cauzat de aplicație (în secunde). Am trasat două grafice de tipul linespoints (puncte și linii între puncte), am plasat legenda în partea din centru dreapta a graficului, am creat etichete pentru legendă și am configurat pentru axa Oy
limitele 0
și 150
.
Un mic ghid de gnuplot găsiți aici: http://www.gnuplotting.org/plotting-data/
Folosind fișierul students.txt dorim afișarea doar a numelui studenților pentru acei studenți care au nota finală 10. Adică a treia coloana are valoarea 10.
Apoi ne propunem să realizăm un script numit extract-sort-grades
pentru a afișa numele studenților, grupa și nota finală pentru acei studenți care au nota finală cuprină între 6 și 9 (inclusiv, adică valorile 6, 7, 8, 9). Adică a treia coloana să aibă valoarea cuprinsă între 6 și 9. Apoi vom sorta intrările în ordinea notei și apoi în ordinea grupei (adică dacă au aceeași notă să fie sortați în ordinea grupei).
Ca bonus, actualizați scriptul extract-name-tab
astfel încât să primească argumente în linia de comandă notele: extract-name-tab 6 9
.
Folosind awk
(sau altă soluție) - extrageți toate notele din fișier și calculați media generală.
Ne propunem să afișăm grupele sortate în funcție de câți studenți din acea grupă au obținut nota 10.
Creați un script numit sort-groups-by-grade
care afișează fiecare grupă și numărul de note de 10 obținute de studenții din acea grupă, separate prin virgulă (,, comma), sortate după numărul de note de 10. Sortarea să fie inversă, adică grupele cu cele mai multe note de 10 să fie primele.
Cautați în pagina de manual a bash șirul Arrays și localizați secțiunea corespunzătoare. Căutați pe Google după șirul bash arrays. Puteți da click pe link.
Acest exercițiu poate fi rezolvat și cu un one liner. Dacă folosiți corespunzător filtre de text precum cut, tr, sed, awk, grep, sort, uniq, veți putea obține aceeași soluție, fără să folosiți array-uri asociative.
Puteți folosi ca intrare fie fișierul students.txt fie fișierul students.csv
În cazul unei implementări corecte, în urma rulării scriptului veți obține output-ul:
314CC,4 311CC,3 315CC,3 313CC,2 312CC,1
Grupa 314CC este prima grupă afișată întrucât are cel mai mare număr de studenți care au obținut nota 10: 4 studenți. Grupa 312CC este ultima grupă afișată întrucât are cel mai mic număr de studenți care au obținut nota 10: 1 student.
Având datele de mai jos:
Date,Open,High,Low,Close 10-03-16,774.25,776.065002,769.5,772.559998 10-04-16,776.030029,778.710022,772.890015,776.429993 10-05-16,779.309998,782.070007,775.650024,776.469971 10-06-16,779,780.47998,775.539978,776.859985 10-07-16,779.659973,779.659973,770.75,775.080017
Se cere graficul de mai jos:
Fișierul /proc/net/dev
conține toate interfețele de rețea care sunt în sistem. Iată exemplu de cum arată:
mihai@wormhole:~$ cat /proc/net/dev Inter-| Receive | Transmit face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed ens33: 401898492 1164147 0 15 0 0 0 0 387589434 843816 0 0 0 0 0 0 lo: 404014153 1015835 0 0 0 0 0 0 404014153 1015835 0 0 0 0 0 0
Fișierul /proc/net/snmp
conține informații despre pachete recepționate de tip TCP/UDP pe sockeții din sistem. Iată un exemplu:
mihai@wormhole:~$ cat /proc/net/snmp Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout Re asmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates Ip: 2 64 1932581 0 4 0 0 0 1925281 1673627 20 8 0 0 0 0 0 0 0 Icmp: InMsgs InErrors InCsumErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddr MaskReps OutMsgs OutErrors OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutA ddrMaskReps Icmp: 46 0 0 45 0 0 0 0 0 1 0 0 0 0 41 0 40 0 0 0 0 1 0 0 0 0 0 IcmpMsg: InType0 InType3 OutType3 OutType8 IcmpMsg: 1 45 40 1 Tcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts InCsumErrors Tcp: 1 200 120000 -1 4228 2576 2818 50 19 1698398 1812313 1563 5 3074 0 Udp: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InCsumErrors IgnoredMulti Udp: 52986 40 0 21899 0 0 0 198401 UdpLite: InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InCsumErrors IgnoredMulti UdpLite: 0 0 0 0 0 0 0 0
Iterați pe conținutul acestor fișiere și afișați datele într-un format cu coloane. Datele vor fi separate printr-un singur spațiu:
iface_name packets_receive packets_transmit drops_receive drops_transmit
InUdpDatagrams InUdpErrors TcpInSegs TcpRetransSegs