Re: Problem with pattern replacing when STRING is an expandable char

2007-12-13 Thread Heinz-Ado Arnolds

Paul Jarc wrote:

Heinz-Ado Arnolds <[EMAIL PROTECTED]> wrote:

a=111.1
echo ${a//[0-9]/x}

correctly gives "xxx.x", but

echo ${a//[0-9]/*}

gives a listing of files in current directory. Seems that the "*"
is expanded before replacing the pattern.


No, it's expanded afterward, because the variable expansion isn't
quoted.  This does what you want:
echo "${a//[0-9]/*}"


It workes the right way at least up to bash-3.1.17(1)-release

But if you set

a=111

it doesn't even work in 3.1.17 right.


3.1.17 behaves the same way as 3.2.25.  You see a different result
because of a different set of files between the two situations, not
because of the different bash version.  If there are no files in the
current directory that match ***.*, then pathname expansion will leave
it unchanged.


paul


Thanks a lot for your fast response! Ok, even after so many years
bash is astounding if you don't have all expansion rules in mind
every time.

Kind regards,

Ado





Re: Problem with pattern replacing when STRING is an expandable char

2007-12-13 Thread Heinz-Ado Arnolds

Mike Stroyan wrote:

Repeat-By:
a=111.1
echo ${a//[0-9]/x}

correctly gives "xxx.x", but

echo ${a//[0-9]/*}

gives a listing of files in current directory. Seems that the "*"
is expanded before replacing the pattern.

It workes the right way at least up to bash-3.1.17(1)-release

But if you set

a=111

it doesn't even work in 3.1.17 right.


  The pathname expansion of "*" is not done until after the parameter
expansion substitution.  That is the documented behavior.  The following
example shows that echo of the "***.*" pattern matches files and
directories that have a "." in their name.  Setting a to "111" results
in a pathname pattern of "***" that matches all of the files.
Double quoting the substitution prevents pathname expansion.

$ echo $BASH_VERSION
3.2.25(1)-release
$ touch a b c.d e.f
$ ls
a  b  c.d  e.f
$ a=111.1
$ echo ${a//[0-9]/*}
c.d e.f
$ echo "${a//[0-9]/*}"
***.*
$ a=111
$ echo ${a//[0-9]/*}
a b c.d e.f
$ echo "${a//[0-9]/*}"
***
$ 


Thanks a lot for your fast response! Ok, even after so many years
bash is astounding if you don't have all expansion rules in mind
every time.

Kind regards,

Ado





Re: Please advise on bash programming tactics/strategy

2007-12-13 Thread Mike Stroyan
On Wed, Dec 12, 2007 at 06:49:25PM -0500, cga2000 wrote:
> 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}')
> 
>   #!/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.

  You can use
 read rxcnt txcnt <<< $netdata
to split out the two values.

  You don't need awk for the splitting of netstat output into words.
The bash read command can do that.
This will split the lines into array a and examine each line.

get_data()
{
local a
netstat -ni |
while read -a a
do
if [[ ${a[0]} == $interface ]] 
then
echo ${a[3]} ${a[4]}
fi
done
}

Or this next version will split the lines into variables and examine them
for matches.  The "d" variable is a dummy placeholder for unused fields.
The last use of "d" variable gets the entire remainder of each line.

get_data()
{
local int d rxcnt txcnt
netstat -ni |
while read int d d rxcnt txcnt d
do
if [[ $int == $interface ]] 
then
echo $rxcnt $txcnt
fi
done
}

  It would be more modular to use an argument to get_data to pass
the interface instead of using the $interface global variable.

get_data()
{
local int d rxcnt txcnt target
target=$1
netstat -ni |
while read int d d rxcnt txcnt d
do
if [[ $int == $target ]] 
then
echo $rxcnt $txcnt
fi
done
}

Then you would invoke it as netdata=$(get_data $interface)

-- 
Mike Stroyan <[EMAIL PROTECTED]>




status of bash_completion

2007-12-13 Thread Matthias Klose
Found http://www.caliban.org/mt/archives/2007/12/please_rescue_m.html
Would anybody be interested to maintain/co-maintain bash_completion?

  Matthias




Re: Please advise on bash programming tactics/strategy

2007-12-13 Thread cga2000
On Thu, Dec 13, 2007 at 12:38:06PM EST, Mike Stroyan wrote:
> On Wed, Dec 12, 2007 at 06:49:25PM -0500, cga2000 wrote:
[..]
> > 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.
> 
>   You can use
>  read rxcnt txcnt <<< $netdata
> to split out the two values.

Very elegant indeed.

And I would never have figured it out from the man page, which states:

"Here Strings

A variant of here documents, the format is:

  <<   You don't need awk for the splitting of netstat output into words.

:-)

Just kidding ..

.. and sincerely hoping someone knowledgeable would show me the right
way to do this.

Needless to say, the solution provided goes way beyond what I hoped.

> The bash read command can do that.
> This will split the lines into array a and examine each line.
> 
> get_data()
> {
> local a
> netstat -ni |
>   while read -a a
>   do
>   if [[ ${a[0]} == $interface ]] 
>   then
>   echo ${a[3]} ${a[4]}
>   fi
>   done
> }

This is very nice!

So I could write in "main" ..

read netdata[0] netdata[1] <<< $(get_data) 

and retrieve my RX/TX packet counts in the netdata array for further
processing!

... not that I need an array in this particular case .. plain
one-dimensional variables would do just as well.

read rxcnt txcnt <<< $(get_data)

> Or this next version will split the lines into variables and examine
> them for matches.  The "d" variable is a dummy placeholder for unused
> fields.

nice ..

> The last use of "d" variable gets the entire remainder of each line.

That I figured, when, while testing, I noticed that my last variable was
polluted by all the orphans/leftovers ..

> get_data()
> {
> local int d rxcnt txcnt
> netstat -ni |
>   while read int d d rxcnt txcnt d
>   do
>   if [[ $int == $interface ]] 
>   then
>   echo $rxcnt $txcnt
>   fi
>   done
> }

... bash feels like such a "jungle" with its countless features (as
compared with C, which has so few it only takes a couple of days to
learn them all..) it's so difficult to figure out a decent way to do
stuff .. 

... or in other words for a beginner like myself, jumping from pseudo
code to actual scripts feels like another quantum leap.

>   It would be more modular to use an argument to get_data to pass
> the interface instead of using the $interface global variable.
> 
> get_data()
> {
> local int d rxcnt txcnt target
> target=$1
> netstat -ni |
>   while read int d d rxcnt txcnt d
>   do
>   if [[ $int == $target ]] 
>   then
>   echo $rxcnt $txcnt
>   fi
>   done
> }
> 
> Then you would invoke it as netdata=$(get_data $interface)

Thank you very much for this mini-tutorial.