Optimalizácia shell skriptov alebo nahradzovanie grep, sed a cut jedným awk

Náhodou som dnes na jednom blogu natrafil na jedej príspevok, kde autor publikoval skript pre zobrazovanie informácií o stave systému v grafickom prostredí. Skript je pekný, ďakujem za inšpiráciu, ale trpí jedným neduhom – príliš komplikované a príliš pomalé získavanie dát.

Pritom optimalizácia je pomerne jednoduchá: stačí lepšie využit vlastnosti jednotlivých nástrojov (prípadne použiť vhodnejší 🙂 ) a celý beh skriptu je možné dramaticky zrýchliť. Pre porovnanie som spravil nasledujúci test a výsledky sú veľmi zaujímavé. Nasledujúci fragment kódu zmeria čas, za ktorý sa zistí počet bajtov prenesených sieťovým rozhraním 10.000 krát.

Stará verzia kódu pred optimalizáciou
$ time for i in `seq 1 10000`; do var_eth0_rx_new=$(cat "/proc/net/dev" | grep eth0 |  sed 's/[a-zA-Z \t:()]\+/ /g' | cut -d ' ' -f 3) ; done
real    6m22.510s
user    0m2.530s
sys     6m14.263s
Nová verzia po jednoduchej optimalizácii
$ time for i in `seq 1 10000`; do var_eth0_rx_new=$( awk -v FS='[ :]+' '$2 == "eth0" { print $3; }' /proc/net/dev ); done
real    1m49.656s
user    0m0.898s
sys     1m48.338s

Vidíme teda, že nový kód beží takmer 3,5x rýchlejšie. Čas, ktorý strávil kernel náročným forkovaním veľkého počtu procesov dramaticky klesol (40.000 forkov v prvom prípade vs. 10.000 forkov v druhom prípade).

Ďalší príklad
-var_load=$(cat /proc/loadavg | cut -d " " -f 1)
+var_load=$(cut -d " " -f 1 /proc/loadavg)

Optimalizujeme teda podľa nasledovných pravidiel:

  1. názov súboru môžeme dať príkazu cut ako parameter, nemusíme používať cat | cut
  2. prvý bod platí aj pre grep, sed a awk
  3. počet rúr | sa snažíme minimalizovať
  4. sekvenciu cat | grep | sed | cut možno poväčšinou nahradiť jedným awk

Jediný pozor si musíme dávať iba vtedy, ak píšeme skript pre viac platforiem. Vtedy je dobré funkčnosť skriptu pred nasadením riadne preveriť, pretože nie každý unix systém má zhodnú verziu awk a taktiež pozor na bashismy.