Beta testers needed


Forum: Programming and Scripting
Topic: Beta testers needed
started by: Zucca

Posted by Zucca on Jan. 24 2008,16:16
Here it is. A system statistics script. Highly customizable.

Copy and paste this and run it with bash. Then post results and comments. Anything is welcome. ;)

Code Sample
#!/bin/bash
# sysinfo.sh

# This script uses /proc filesystem and at least following utilities:
# sed, perl/bc and grep
#
# Run from command line with --help switch to get more help.

# Feel free to change this if you are too lazy to set an alias.;)
# Note: You can have custom ouput from command line too. Just see --help.
DEFAULT_FORMAT="Uptime: -UPTIME- | % idle since boot: -IDLEPERCENT- | \
-CPUMODEL- @ -CPUSPEED- | \
Bogomips: -BOGOMIPS- | \
Mem total/used/free: -MEMTOTAL-/-MEMUSAGE-/-MEMFREE-"

# No need to edit more. =)
############################################################################


BASENAME=`basename $0`
VERSION="1.10.1b"

case $@ in

*--licence*)
# We saw user requesting lience...
echo "$BASENAME version $VERSION

############################################################################
### LICENCE -start- ########################################################
############################################################################
#
#Copyright (c) 2008, Zucca
#
# All rights reserved.
#Redistribution and use in source and binary forms, with or without
#modification, are permitted provided that the following conditions are met:
#   - Redistributions of source code must retain the above copyright notice,
#     this list of conditions and the following disclaimer.
#   - Redistributions in binary form must reproduce the above copyright
#     notice, this list of conditions and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#   - Neither the name of the Zucca's company nor the names of its
#     contributors may be used to endorse or promote products derived from
#     this software without specific prior written permission.
#
#       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
#       CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,
#       INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
#       MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
#       DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
#       CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
#       SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
#       NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
#       LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
#       HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
#       CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
#       OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#       SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
############################################################################
### LICENCE -end- ##########################################################
############################################################################
";;

*--help*)
# User wants some help...
echo "${BASENAME} version $VERSION

USAGE: ${BASENAME} [--uptimeweeks] [--mmega] [OUTPUT FORMAT]
USAGE: ${BASENAME} [--help]
USAGE: ${BASENAME} [--licence]

OUTPUT FORMAT can have any text you like (${BASENAME} will use echo with \
no argument to print information, so use your head.), but ${BASENAME} will \
replace following:\n\
-UPTIME- will show system uptime. --uptimeweeks will tell uptime in weeks \
if uptime is seven days or more.
-IDLEPERCENT- displays percentage of idle time from uptime.
-CPUMODEL- diplays your CPU model.
-CPUSPEED- displays the clockspeed of your processor.
-CPUCACHE- shows size of your CPU cache.
-BOGOMIPS- see http://en.wikipedia.org/wiki/Bogomips
-MEMTOTAL- will display amout of total physical (RAM) memory in your system.
-MEMUSAGE- same as above but displays used memory
-MEMFREE- same as above but displays free memory

Note: switches can be in any order as long as they are before OUTPUT FORMAT

Example: ${BASENAME} -UPTIME-
will show you uptime in days, hours, minutes and seconds.

If OUTPUT FORMAT does not contain any text it defaults to:
${DEFAULT_FORMAT}"
;;

*)
   # Allright! Let's bang a gong and get it on!
   
   if [ ! -d "/proc" ]
   then
       echo -e "No proc filesystem found.\nCannot continue."
       exit 1
   fi
   
   # calculator function
   function calc {
       
       # First test if $CALCEXE contains any information if not then set a
       # value. Is this a good (fast/efficient) way to do it?
       test -n "$CALCEXE" || CALCEXE=`which perl` || CALCEXE=`which bc` || CALCEXE="FAIL"
       
       case $CALCEXE in
       *perl)
           $CALCEXE -e "printf '%.${DECIMALS}f',${@}"
       ;;
       *bc)
           echo -e "scale=$DECIMALS\n${@}" | $CALCEXE
       ;;
       FAIL)
           echo -n "Could not calculate: excutable missing"
           exit 1
       ;;
       esac
   }
   
   function addresult {
       # Search and replace marked places of OUTPUT FORMAT with
       # correcponding values.
       OUTPUT_FORMAT=`echo "$OUTPUT_FORMAT" | sed -e "s/-$1-/$2/g"`
   }
   
   if [ -n "$*" ]
   then
       ARGS="$*"
   else
       ARGS="."
   fi
   
   if echo $ARGS | grep "\-\-" > /dev/null
   then
       OUTPUT_FORMAT=${ARGS##*--}
       OUTPUT_FORMAT=${OUTPUT_FORMAT#* }
       if echo "$OUTPUT_FORMAT" | grep -v "\-*\-" > /dev/null
       then
           OUTPUT_FORMAT="."
       fi
   else
       OUTPUT_FORMAT=$ARGS
   fi
   
   if [ "$OUTPUT_FORMAT" == "." ]
   then
       OUTPUT_FORMAT="$DEFAULT_FORMAT"
   fi
   
   # Case-hell starts here.;P
   
   case $OUTPUT_FORMAT in *-UPTIME-*)
       
       UPTIME=""
       
       TOTSECS=`PROCUPTIME=$(cat /proc/uptime) && echo ${PROCUPTIME%%.*}`
       let "SECS=${TOTSECS}%60"
       let "MINS=${TOTSECS}/60%60"
       let "HOURS=${TOTSECS}/3600%24"
       
       
       if echo "$ARGS" | grep -i "\-\-uptimeweeks" > /dev/null
       then
           let "DAYS=${TOTSECS}/86400%7"
           let "WEEKS=${TOTSECS}/604800"
       else
           let "DAYS=${TOTSECS}/86400"
       fi
       
       if [ -n "$WEEKS" ] && [ "$WEEKS" != "0" ]
       then
           UPTIME="${UPTIME}${WEEKS}w"
       fi
       if [ "$DAYS" != "0" ]
       then
           UPTIME="${UPTIME}${DAYS}d"
       fi
       UPTIME="${UPTIME}${HOURS}h${MINS}m${SECS}s"
       
       addresult "UPTIME" "$UPTIME"
   ;; esac
   
   
   case $OUTPUT_FORMAT in *-IDLEPERCENT-*)
   
       DECIMALS="4"
       
       # This tests if PROCUPTIME is already set.
       # It already should have some value if user has requested -UPTIME- from
       # the command line
       if [ -z $PROCUPTIME ]
       then
           PROCUPTIME=`cat /proc/uptime`
           TOTSECS=${PROCUPTIME%%.*}
       fi
       
       # Parse and calculate
       IDLESECS=${PROCUPTIME#* }
       IDLESECS=${IDLESECS%.*}
       IDLEPERCENT=`calc $IDLESECS/$TOTSECS*100`
       IDLEPERCENT="${IDLEPERCENT}%"
       
       addresult "IDLEPERCENT" "$IDLEPERCENT"
   ;; esac

############################################################################
### Memory related part - start ############################################
############################################################################

   function parsememinfo {
       
       # Get memory information if there isn't already
       test -z "$MEMINFO" && MEMINFO=`cat /proc/meminfo`
       PARSED=${MEMINFO#*$*:}
       PARSED=${PARSED%% kB*}
       # echo $PARSED
   }
   
   function memfree {
       parsememinfo "MemFree"
       MEMFREE=$PARSED
       parsememinfo "Cached"
       CACHED=$PARSED
       parsememinfo "Buffers"
       BUFFERS=$PARSED
       let "MEMFREE=${MEMFREE}+${CACHED}+${BUFFERS}"
       MEMFREERAW=$MEMFREE
   }
   
   function memsuffix {
       test -n "$MEMSUFFIX" || case $ARGS in
       *--mmega*)
           MEMSUFFIX="MB";;
       *)
           MEMSUFFIX="kB";;
       esac
   }

   case $OUTPUT_FORMAT in *-MEMFREE-*)
       # Count free memory

       # As far as I know anything about memory
       # egrep "^Cached:|^MemFree:|^Buffers:" /proc/meminfo
       # shows the actual free memory.
       # So this script will count the sum of those values
       
       memfree
       memsuffix
       test "$MEMSUFFIX" == "MB" && let "MEMFREE=$MEMFREE/1024"
       MEMFREE="${MEMFREE}${MEMSUFFIX}"
       
       addresult "MEMFREE" "$MEMFREE"
   ;; esac
   
   case $OUTPUT_FORMAT in *-MEMTOTAL-*)
       # Count total memory
       parsememinfo "MemTotal"
       MEMTOTAL=$PARSED
       
       memsuffix
       MEMTOTALRAW=$MEMTOTAL
       test "$MEMSUFFIX" == "MB" && let "MEMTOTAL=$MEMTOTAL/1024"
       MEMTOTAL="${MEMTOTAL}${MEMSUFFIX}"
       
       addresult "MEMTOTAL" "$MEMTOTAL"
   ;; esac
   
   case $OUTPUT_FORMAT in *-MEMUSAGE-*)
       # Count memory usage
       
       test -n $MEMFREERAW || memfree
       test -n $MEMTOTALRAW || parsememinfo MemTotal && MEMTOTALRAW=$PARSED
       let "MEMUSAGE=$MEMTOTALRAW-$MEMFREERAW"
       memsuffix
       test "$MEMSUFFIX" == "MB" && let "MEMUSAGE=$MEMUSAGE/1024"
       MEMUSAGE="${MEMUSAGE}${MEMSUFFIX}"
       
       addresult "MEMUSAGE" "$MEMUSAGE"
   ;; esac
   
############################################################################
### Memory related part - end # CPU related part - start ###################
############################################################################
   
   # function to parse /proc/cpuinfo
   function parsecpuinfo {
       
       # test -n "$TAB" || TAB=`echo -ne "\t"`
       
       # Get CPUinfo if we don't have it yet
       test -z "$CPUINFO" && CPUINFO=`cat /proc/cpuinfo`
       PARSED=`echo "$CPUINFO" | grep "$@"`
       PARSED=${PARSED##*: }
       # echo $PARSED
   }
   
   case $OUTPUT_FORMAT in *-CPUMODEL-*)
       parsecpuinfo "model name"
       addresult "CPUMODEL" "$PARSED"
   ;; esac
   
   case $OUTPUT_FORMAT in *-CPUSPEED-*)
       parsecpuinfo "cpu MHz"
       addresult "CPUSPEED" "${PARSED}MHz"
   ;; esac
   
   case $OUTPUT_FORMAT in *-BOGOMIPS-*)
       parsecpuinfo "bogomips"
       addresult "BOGOMIPS" "$PARSED"
   ;; esac
   
   case $OUTPUT_FORMAT in *-CPUCACHE-*)
       parsecpuinfo "cache size"
       addresult "CPUCACHE" "$PARSED"
   ;; esac

############################################################################
### CPU related part - end #################################################
############################################################################
   
   # Finally echo all the requested statistics
   echo -e "$OUTPUT_FORMAT"
;;
# Here it ends.
esac

Posted by mikshaw on Jan. 24 2008,22:29
I attempted to test it, but DSL doesn't have bc and I haven't bothered to install it.

I did get a little info, though:
Uptime: 9h54m23s | Uptime load average:  | Mem total/used/free: 515304kB/105724kB/409580kB

Posted by Zucca on Jan. 24 2008,22:43
You can customize how it outputs statistics. run it with --help.
Anyway. I have developed it much. I want to finish it fast. ;)
New version will be here soon.
BTW. if DSL does not have bc, then is it possible to have decimals when calculating with "let"?

Here's a "shot" from new version:
Quote
zucca@zelan ~/scripts/bash $ sh sysinfo.sh --help
sysinfo.sh version 1.8b

USAGE: sysinfo.sh [--uptimeweeks] [--mmega] [OUTPUT FORMAT]
USAGE: sysinfo.sh [--help]

OUTPUT FORMAT can have any text you like (sysinfo.sh will use echo with no argument to print information, so use your head.), but sysinfo.sh will replace following:
-UPTIME- will show system uptime. --uptimeweeks will tell uptime in weeks if uptime is seven days or more.
-UPTIMELA- will show load average of whole uptime (this may not be accurate)
-CPUMODEL- diplays your CPU model
-CPUSPEED- displays the clockspeed of your processor
-CPUCACHE- shows size of your CPU cache
-BOGOMIPS- see < http://en.wikipedia.org/wiki/Bogomips >
-MEMTOTAL- will be replaced with amout of total physical (RAM) memory in your system
-MEMUSAGE- same as above but displays used memory
-MEMFREE- same as above but displays free memory

Note: switches can be in any order as long as they are before OUTPUT FORMAT

Example: sysinfo.sh -UPTIME-
will show you uptime in days, hours, minutes and seconds.

If OUTPUT FORMAT does not contain any text it defaults to:
Uptime: -UPTIME- | Uptime load average: -UPTIMELA- | -CPUMODEL- @ -CPUSPEED- | Bogomips: -BOGOMIPS- | Mem total/used/free: -MEMTOTAL-/-MEMUSAGE-/-MEMFREE-
zucca@zelan ~/scripts/bash $ sh sysinfo.sh --mmega
Uptime: 1d3h10m47s | Uptime load average: 0.3740 | Pentium III (Coppermine) @ 896.126MHz | Bogomips: 1793.84 | Mem total/used/free: 499MB/290MB/209MB

Posted by curaga on Jan. 25 2008,22:52
Quote
is it possible to have decimals when calculating with "let"?
Nah

Posted by WDef on Jan. 26 2008,01:21
Hi Zucca

Suggestions:

1.  You can use the -q option to grep to shut it up rather than redirecting to /dev/null all the time.

2.   You might want to investigate the use of "case" instead of repeatedly parsing the arguments which is inefficient (or use getopts).

3. Command substitution using Perl or awk are easy ways to do floating point arithmetic (ie decimals) in a shell script  - there's no need to resort to bc (but everyone seems to forget this and pull out bc).

eg .. say I want to add 1.35 to 6.78 and divide by 9.1 and these numbers are in  shell vars a,b,c respectively, and I want to put the result in var d:

Code Sample
d=$(echo "$a $b $c" | awk '{printf ($1 + $2 )/ $3 }')


echo $d gives 0.913187

To round to 2 dec places:

Code Sample
d=$(echo "$a $b $c" | awk '{printf "%1.2f", ($1 + $2 )/ $3 }')


Or doing a similar command substitution using Perl (no echo needed):

Code Sample
d=$(perl -e "print (($a + $b) / $c)")


To round to 2 dec places:

Code Sample
d=$(perl -e "printf  '%.2f', (($a + $b) / $c)")


echo $d yields:

0.91

Look up printf to understand the precision modifier (number of dec places).

No bc needed!

Posted by ^thehatsrule^ on Jan. 26 2008,01:55
1. fyi, from grep man page:
Quote
Suppress error messages about nonexistent or unreadable files. Portability note: unlike GNU grep, traditional grep did not conform to POSIX.2 , because traditional grep lacked a -q option and its -s option behaved like GNU grep's -q option. Shell scripts intended to be portable to traditional grep should avoid both -q and -s and should redirect output to /dev/null instead.

Posted by WDef on Jan. 26 2008,02:00
Does this script need to run on non-GNU systems?
Posted by Zucca on Jan. 27 2008,21:02
Well I have one friend who might want to test this on Mac OS X.
I don't know even  if OSX has the /proc filesystem...
Anyway first priority is to get this working on Linux with minimal depencies.

Posted by humpty on Jan. 28 2008,16:54
it doesn't look like you actually need the decimal places,
you can probably get away with just integer arithmetic;
i.e
secs=`expr $totalsecs / 60`

Posted by Zucca on Jan. 28 2008,17:50
I don't need it there.
I will need decimals where I calculate percentual value of non-idle time from uptime (that will replace -UPTIMELA-).
Perl seems to be quite neat solution anyways.

I just came from dentist and half of my face is numb... Also my thinking is at least 10 times slower... I'll be back again tomorrow. ;)

Posted by Zucca on Jan. 29 2008,13:54
Some improvements

I'm currently replacing as many if+grep combinations as possible with case statement, but is there a way to make case go trough _every_ <pattern>) <code to execute> that meets the criteria?
Here's an example:
Code Sample
PATTERN="one two three"
case $PATTERN in
*one*)
 echo "One matched";;
*two*)
 echo "Two matcched";;
*three*)
 echo "Three matched";;
esac

Now it only echoes "One matched". I would like it to echo all of those. Any way possible with _one_ case statement?

And I impoved calculation a bit with a nice function:
Code Sample
   # calculator function
   function calc {
       
       # First test if $CALCEXE contains any information if not then set a
       # value. Is this a good (fast/efficient) way to do it?
       test -n "$CALCEXE" || CALCEXE=`which perl` || CALCEXE=`which bc` || CALCEXE="FAIL"
       
       case $CALCEXE in
       *perl)
           $CALCEXE -e "printf '%.${DECIMALS}f',${@}"
       ;;
       *bc)
           echo -e "scale=$DECIMALS\n${@}" | $CALCEXE
       ;;
       FAIL)
           echo -n "Could not calculate: excutable missing"
           exit 1
       ;;
       esac
   }

I think it's quite lightweight. I would like to add awk also there if it can calculate same way as perl and bc. I read somewhere that awk is more common on *NIX systems than perl or bc.
Only basic calculation operators are needed: + - * and /, plus decimal support. I would also like to replace sed with awk if it can perform search & replace easily, like sed.
So anyone who knows awk, please tell. =)

Posted by mikshaw on Jan. 29 2008,15:29
Quote
Now it only echoes "One matched". I would like it to echo all of those. Any way possible with _one_ case statement?
Case doesn't work that way. It compares the string to each option in order, and stops when it finds a match.

You can accomplish what you need in a loop:
Code Sample
for i in $PATTERN; do
case $i in
one) echo "One matched";;
two) echo "Two matched";;
three) echo "Three matched";;
esac
done
This may not be the most efficient way, but it should work.

Posted by Zucca on Jan. 29 2008,16:47
Quote (mikshaw @ Jan. 29 2008,12:29)
You can accomplish what you need in a loop:
Code Sample
for i in $PATTERN; do
case $i in
one) echo "One matched";;
two) echo "Two matched";;
three) echo "Three matched";;
esac
done
This may not be the most efficient way, but it should work.

Well I think many case-sentences in a row might be more efficient.
But I could test it with time command. =)

Posted by Zucca on Jan. 29 2008,17:17
Results

I tested with this bash code:
Code Sample
echo "With for -loop"
time for i in $@
do
 case $i in
   1) echo 1;;
   2) echo 2;;
   3) echo 3;;
   4) echo 4;;
   5) echo 5;;
   6) echo 6;;
   7) echo 7;;
   8) echo 8;;
   9) echo 9;;
   ten) echo ten;;
 esac
done

echo "Cases in a row"
time (
case $@ in
 *1*) echo 1;;
esac
case $@ in
 *2*) echo 2;;
esac
case $@ in
 *3*) echo 3;;
esac
case $@ in
 *4*) echo 4;;
esac
case $@ in
 *5*) echo 5;;
esac
case $@ in
 *6*) echo 6;;
esac
case $@ in
 *7*) echo 7;;
esac
case $@ in
 *8*) echo 8;;
esac
case $@ in
 *9*) echo 9;;
esac
case $@ in
 *ten*) echo ten;;
esac
)


And here's when I ran it:
Quote
$ sh test.sh 1 2 3 4 5 6 7 8 9 ten
With for -loop
1
2
3
4
5
6
7
8
9
ten

real    0m0.006s
user    0m0.000s
sys     0m0.000s
Cases in a row
1
2
3
4
5
6
7
8
9
ten

real    0m0.007s
user    0m0.000s
sys     0m0.000s


I have to say that I was a bit surprised. =) I ran that many times. Times got a bit different each time, but for loop+case won each time.

I need open several other processes to make CPU more busy to get more accurate results.

Edit: Ok. There was no singnificant difference. Maybe lowering clockspeed will show more...

Posted by ^thehatsrule^ on Jan. 29 2008,17:29
Quote
I have to say that I was a bit surprised. =) I ran that many times. Times got a bit different each time, but for loop+case won each time.
That's not too surprising actually... in your many cases script it continously passes all the arguments and looks through all of them each time, whereas the for loop implementation doesn't have wildcards in the case statement and only compares one parameter at a time.  And having a loop like that seems to be pretty common to me.

Quote
I would also like to replace sed with awk if it can perform search & replace easily, like sed.
I'd stick with sed because it should be a 'lighter' binary (unless you have some reason to worry about having a missing sed)

Also, if you can, avoid using search and replace at all if possible.    For example, looking at your code in your first post, you can make a function that can print the output from variables instead of replacing the text in OUTPUT_FORMAT.

Posted by Zucca on Jan. 29 2008,18:23
Quote (^thehatsrule^ @ Jan. 29 2008,14:29)
Quote
I would also like to replace sed with awk if it can perform search & replace easily, like sed.
I'd stick with sed because it should be a 'lighter' binary (unless you have some reason to worry about having a missing sed)

Also, if you can, avoid using search and replace at all if possible.    For example, looking at your code in your first post, you can make a function that can print the output from variables instead of replacing the text in OUTPUT_FORMAT.

Yes. Just because of that. I've read that awk is more common than sed.
From Wikipedia:
Quote
A version of the AWK language is a standard feature of nearly every modern Unix-like operating system available today.
Quote
Besides the Bourne shell, AWK is the only other scripting language available in a standard Unix environment.

But now when you said that sed is lighter, I'll plan my script primary to look for sed, and then awk. =)

About for+case:
I think I have to stick with multiple cases. If I pass OUTPUT_FORMAT for for -loop to go trough and
then if/when sed/awk modifies it (still insife for -loop), for -loop won't know it's been modified. Right?
Then case inside for -loop might have to modify same information, bit in different place (in OUTPUT_FORMAT), more than once. Ok. Cituation like this is rare.Possible only is user has specified same spot (-UPTIME- for example) more than once.
With many case -sentences OUTPUT_FORMAT is modified instantly if any of the case -sentences is triggered.

Anyway tests that I performed showed very little difference, so I think this "performance tweaking" with for-case vs. many cases isn't really relevant anymore. I'd like to focus more to make this script to work on as many platforms/OSes as possible, meaning to make this use most common UNIX tools awailable.. ;) Many thanks anyway.

And I will need the search and replace because user running this script can specify his/her own output from the command line ie: ./sysinfo.sh "Uptime: -UPTIME- | Free RAM: -MEMFREE-"
Basically sed (maybe awk also) is there to search & replace user defined command line arguments.

Get it? ;)

Ok. Enough long post already. Brb going to moon.

Posted by ^thehatsrule^ on Jan. 29 2008,19:05
Quote
And I will need the search and replace because user running this script can specify his/her own output from the command line ie: ./sysinfo.sh "Uptime: -UPTIME- | Free RAM: -MEMFREE-"
Basically sed (maybe awk also) is there to search & replace user defined command line arguments.
How often are you going to use those custom lines?  If you really want to be somewhat more efficient you could only use sed/awk when you have custom lines instead (or somehow specify and eval given variables on the command line?).  It really depends on how much you want to spend on this.

Posted by Zucca on Jan. 29 2008,19:39
That's true. It would be more efficient that way. It may be a bit complex to implement, but I'll try it some time. =)
Posted by Zucca on Jan. 29 2008,20:07
New relase

Some if+grep statements still need to change.
And as usual, comments and suggestions are very welcome. ;)

< Go to first post to get it >

Posted by Zucca on Jan. 30 2008,13:04
Bug spotted.
It does not result to any error. But as I ran that script with bash -x I could see how it uses cat to get information from /proc even if specific information is already there. It makes this script slower. Even I have code to check if script already has the information needed, it still goes to fetch the information again.
Here's an example code where it fails to regonize that the data is already there:
Code Sample
   function parsememinfo {
       
       # Get memory information if there isn't already
       if [ -z "$MEMINFO" ]
       then
           MEMINFO=`cat /proc/meminfo`
       fi
       PARSED=${MEMINFO#*$*:}
       PARSED=${PARSED%% kB*}
       echo $PARSED
   }


Any of you have any solution to this?
First the code was like this: test -z $VARIABLE && VARIABLE="data"
and it didn't worked any better than the code above.

Posted by curaga on Jan. 30 2008,17:22
I read somewhere that some versions of bash can only use -z with number variables.

Try:

if [ ! -n "$MEMINFO" ]

aka not not null.

Posted by ^thehatsrule^ on Jan. 30 2008,17:23
I think that's because $() uses a subshell in order to execute the command substitution... so the variable is lost afterwards.

Since you really only need to read that file once, the easiest change would be to read it before you call that function.

EDIT: saw previous post:
Quote
I read somewhere that some versions of bash can only use -z with number variables.

Try:

if [ ! -n "$MEMINFO" ]

aka not not null.
You mean for test, not bash..? Also, -z is for strings only (and if it wasn't, an error would be printed).  For the most portability, = should be used iirc.

Posted by WDef on Jan. 30 2008,23:52
Zucca: re using awk to do real arithmetic - I thought I did show you how to - go back and re-read my post, the same one with Perl.

Perl vs Awk: a *nix system without Perl is rare indeed.

Re: sed vs awk.  The usual rule is you try to avoid sed for anything except simple replacements, which it is usually best for.   But really, it doesn't much matter on modern processors unless an operation is in a lengthy loop or is otherwise chewing up a lot of resources.

Posted by mikshaw on Jan. 31 2008,00:30
I think the only thing I've ever used sed for was replacement. I don't even know what else it does =o)
Posted by Zucca on Jan. 31 2008,15:06
Quote (^thehatsrule^ @ Jan. 30 2008,14:23)
I think that's because $() uses a subshell in order to execute the command substitution... so the variable is lost afterwards.

But I don't have any "$(command)" there.
I read that to set the variable local only you must use local -command.

But if it is really lost somewhere, is there a way to pass it to the outer process?

Posted by ^thehatsrule^ on Jan. 31 2008,16:58
Quote (Zucca @ Jan. 31 2008,10:06)
Quote (^thehatsrule^ @ Jan. 30 2008,14:23)
I think that's because $() uses a subshell in order to execute the command substitution... so the variable is lost afterwards.

But I don't have any "$(command)" there.
I read that to set the variable local only you must use local -command.

But if it is really lost somewhere, is there a way to pass it to the outer process?

Well, `` does the same thing as $() or maybe you weren't looking where parsememinfo was being called (in the memfree function)?

It's not local variables that you are looking at right now... it's the child subshell(?) that cannot pass a variable (directly) to a parent - hence my original suggestion.

Posted by Zucca on Jan. 31 2008,17:37
Ok. I think now how I will manage this problem...
Posted by WDef on Feb. 01 2008,01:38
The easiest way to get a variable value out of a command substition is to echo it into a variable.

Say I have a function func that produces a result in variable RES, and I call func via command substitution (hence in a subshell).  I can get RES into ANSWER this way:
Code Sample

func(){
# blah
RES=5
echo $RES
}

ANSWER=$(func)


In long messy scripts, this can be a good way to pass variables out of functions without getting mixed up global variables.  Klaus Knopper does this all the time.

Note anything written to stdout from func will go into ANSWER, not to the terminal.

If you need something in func to go to the terminal and not go into ANSWER, re-direct that line's stdout to /dev/tty

Posted by Zucca on Feb. 04 2008,21:28
New version.

I made it faster by modifying functions.
Those who like to test it will find it from < here >.

As always, bug reports are welcome. =)

Powered by Ikonboard 3.1.2a
Ikonboard © 2001 Jarvis Entertainment Group, Inc.