bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Please advise on bash programming tactics/strategy


From: cga2000
Subject: Re: Please advise on bash programming tactics/strategy
Date: Wed, 12 Dec 2007 18:49:25 -0500
User-agent: Mutt/1.5.13 (2006-08-11)

On Wed, Dec 12, 2007 at 12:31:47AM EST, Bob Proulx wrote:
> cga2000 wrote:
> > I was wondering if there is any way I can convince netstat to return
> > its output to bash variables for additional processing.
> 
> Do you mean like this?
> 
>     rxcnt=$(netstat -ni | awk '/^eth0/{print$4}')

Precisely.  Funny I keep forgetting this very powerful feature of bash.
> 
> > Pretty simple logic:
> > 
> > Do forever:
> > 
> >   Call netstat to obtain RX & TX byte counts for eth0 Print delta
> >   {current .. minus previous .. byte counts} Save current byte
> >   counts Wait for a second or so ..
> 
> Such as like this?
> 
>   #!/bin/sh

[..]

>   exit 0

Excellent! 

I adapted the above and came up with this:

  #!/bin/sh

  interface=eth0

  get_data()
  {
    netstat -ni | awk '/^'"$interface"'/{print$4,$8}'
  }

  init_data()
  {
    netdata=$(get_data)
    prevrxcnt=$(echo $netdata | awk '{print$1}')
    prevtxcnt=$(echo $netdata | awk '{print$2}')
  }

  save_data()
  {
    netdata=$(get_data)
    rxcnt=$(echo $netdata | awk '{print$1}')
    txcnt=$(echo $netdata | awk '{print$2}')
    diffrxcnt=$(($rxcnt - $prevrxcnt))
    difftxcnt=$(($txcnt - $prevtxcnt))
    prevrxcnt=$rxcnt
    prevtxcnt=$txcnt
  }

  init_data
  while sleep 1; 
  do
    save_data
    echo $diffrxcnt $difftxcnt | 
    awk '{printf "%4.1f k/s %4.1f k/s\n",$1*576/1024,$2*567/1024}'
  done

  exit 0

I provides exactly the output I need .. although bash must provide a 
more elegant (and less expensive) way to split a variable that contains
two fields separated by a space than invoking awk.

;-(

I would have liked to take the packets-to-kilobytes conversion out of
the last awk invocation, but then it looks like bash only does integer
arithmetic.

In any event any suggestions how I could improve the above is very
welcome.

> I would not normally use global variables like this but it was
> specifically what you were asking so I used them.  Normally I prefer
> to avoid global variables except for global configuration data.  Being
> able to trace the flow through the code as you read it is very
> important to the long term maintainability IMNHO.  So generally I
> advise to write the code such as to avoid using globals.

Yes, but I don't see how this could be done in bash if you'd rather
have something modular.

Naturally, one way to get rid of global variables would be to rewrite
the above like so:

#!/bin/sh

interface=eth0

get_data()
{
  netstat -ni | awk '/^'"$interface"'/{print$4,$8}'
}

netdata=$(get_data)
prevrxcnt=$(echo $netdata | awk '{print$1}')
prevtxcnt=$(echo $netdata | awk '{print$2}')

while sleep 1; do
  netdata=$(get_data)
  rxcnt=$(echo $netdata | awk '{print$1}')
  txcnt=$(echo $netdata | awk '{print$2}')
  diffrxcnt=$(($rxcnt - $prevrxcnt))
  difftxcnt=$(($txcnt - $prevtxcnt))
  prevrxcnt=$rxcnt
  prevtxcnt=$txcnt
  echo $diffrxcnt $difftxcnt | 
  awk '{printf "%4.1f k/s %4.1f k/s\n",$1*576/1024,$2*567/1024}'
done

exit 0

But then, this is beginning to look as cryptic as my initial one-liner.

> > I initially thought I could just pipe the "netstat -in" command to
> > the invocation of a bash function.
> 
> Yes?
> 
>   filter_data() { awk '/^'"$interface"'/{print$4}' ;}
> 
>   get_data() { netstat -ni | filter_data ;}
> 
> > The function would have taken care of the gory details of parsing &
> > formatting the output of the netstat command and then stored the
> > current byte counts where they would be available for the next time
> > the function is invoked.
> 
> Oh, stored, global variables, blech, but okay.
> 
>   grab_data() { prevrxcnt=$(awk '/^'"$interface"'/{print$4}') ;}
> 
> > The trouble is that I haven't been able to find anything like a
> > "static" local variable -- ie. variables that are not reinitialized
> > every time the function is invoked.
> 
> In C static variables are global to the compilation unit.  In bash the
> entire script is the compilation unit.  In C static variables are not
> visible across compilation units.  In bash there is no individual
> compilation with a separate link step.
> 
> Traditionally a naming convention such as applying the name of the
> function to the variable name is used to make sure that name
> collisions are avoided.
> 
> > Is there such a thing?  Or is there any way the function could save
> > the current byte counts to global variables?  
> 
> See my examples.  Or did I miss the point of the question entirely?

Oh, no .. spot on!   

After you'd shown me how I could assign the parsed output of netstat to
variables, and since you kindly provided a sample script that worked out
of the box, there was little left for me to do..

Thanks much for your help.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]