1#!/usr/bin/perl 2# 3# i3blocks-bandwidth.pl 4# 5# Get network throughput from /sys/class/net and convert it to readable format. 6# Keeps the text at a constant width regardless of the magnitude or units. This 7# is useful for i3bar with you don't want widgets changing width, but it could 8# also be used for other indicators or just as a quick shell script. 9# 10# Usage: i3blocks-bandwidth.pl INTERFACE 11# test 9198 (can be any float or integer) 12# test {1..1000} (using shell expansion) 13# 14# Note that Perl's printf doesn't round properly for numbers like 0.95 (i.e. 15# 0.95 -> 0.9b not 1.0b). However, it is a lot faster than implementing a 16# custom rounding function. Accuracy doesn't matter much in this case. Also, 17# this script works best with a refresh rate of 1 second. It doesn't have to 18# be exact, but larger/smaller values give misleading averages. 19# 20 21use strict; 22use warnings; 23 24my$temppath="/dev/shm/bandwidth-$ARGV[0]"; 25 26offline()if($#ARGV<0);# fail if no interface is specified 27 28if($ARGV[0]eq"test") {# see comment at top of file 29shift; 30foreach(@ARGV) { 31 parse($_); 32print"\n"; 33} 34exit; 35} 36 37# Check if interface is up 38open(STFILE,"/sys/class/net/$ARGV[0]/operstate")or offline(); 39my$state= <STFILE>; 40close(STFILE); 41$state=~m/\A([^:\s]+)/; 42offline()if($1ne"up"); 43 44sub offline { 45print"<span color='#ff0000'>"; 46print"down"; 47print"</span>"; 48exit; 49} 50 51# Get rx bytes 52open(BYTES,"/sys/class/net/$ARGV[0]/statistics/rx_bytes")or offline(); 53my$rx_bytes= <BYTES>; 54close BYTES; 55chomp$rx_bytes; 56 57# Get tx bytes 58open(BYTES,"/sys/class/net/$ARGV[0]/statistics/tx_bytes")or offline(); 59my$tx_bytes= <BYTES>; 60close(BYTES); 61chomp$tx_bytes; 62 63# Get current time 64my$time=time; 65 66if(-f $temppath) {# Read then overwrite file 67open(BYTES,$temppath); 68my$oldcontent= <BYTES>;# read old data 69close(BYTES); 70open(my$fh,'>',$temppath); 71print$fh"$time$rx_bytes$tx_bytes";# write new data 72close$fh; 73my($oldtime,$oldrx,$oldtx) =split/ /,$oldcontent; 74my$dt=$time-$oldtime; 75my$drxdt= ($rx_bytes-$oldrx) /$dt*8;# *8 converts bytes to bits 76my$dtxdt= ($tx_bytes-$oldtx) /$dt*8; 77 parse($drxdt); 78print" / "; 79 parse($dtxdt); 80}else{# Write data and exit 81open(my$fh,'>',$temppath); 82print$fh"$time$rx_bytes$tx_bytes"; 83close$fh; 84chmod0666,$temppath; 85exit; 86} 87 88sub parse {# Determine best units and call round() 89my($val) =@_; 90if($val==0) { 91print"000b"; 92}elsif($val<999.5) {# bits/second 93 round($val,"b"); 94}elsif($val<999500) {# kilobits/second 95 round($val/1000,"k"); 96}elsif($val<999500000) {# megabits/second 97 round($val/1000000,"M"); 98}else{ 99 round($val/10000000000,"G"); 100} 101} 102 103sub round {# Format to the correct number of characters 104my($val,$suffix) =@_; 105if($val<9.95) { 106printf("%.1f%s",$val,$suffix);# *.* 107}elsif($val<99.5) { 108printf("0%.0f%s",$val,$suffix);# 0** 109}else{ 110printf("%.0f%s",$val,$suffix);# *** 111} 112}