Re: Problem with pattern replacing when STRING is an expandable char
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
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
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
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
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.