Link to home
Start Free TrialLog in
Avatar of hengesystems
hengesystems

asked on

Help need with Bash script to read numbers from various files and output these to html table.

I am trying to complete the following script which reads files from various directories and produces an HTML table.

The script is mostly working, however I would like the following adjustments:


1.  the  DISKSHARES variable is not evaluating to anything.  It needs more complex file preprocessing.  The other variables simply read the relevant file.

/proc/vmware/vm/$i/disk/vmhba0\:0\:0  will contain something like:

    shares       cmds      reads
      1000     163505      10465

I would like DISKSHARES to equal 1000 in this case.

At the moment, DISKSHARES is just blank. Im not really sure what I am doing with the read command.

I would also like the script to display the current date and time at the top.

2. Once DISKSHARES is working, I would like an additional table outputed below this to  display relative values using asterixes rather than numbers  

For example:

Instead of

VM         CPU           MEM            DISK
             SHARES      SHARES       SHARES

machine1   100        3                 5
machine2   200        2                 15
mashine3   300        1                 10


It would display:


VM         CPU           MEM            DISK
             SHARES      SHARES       SHARES

machine1   *          ***               *
machine2   **        **                 ***
mashine3   ***      *                   *


Hope someone can help.


Here is the script so far:

#!/bin/bash

echo Content-type: text/plain
echo ""

WORLDLIST=`ls -1 /proc/vmware/vm/`
ACTIVELIST=`for i in $WORLDLIST; do cat /proc/vmware/vm/$i/cpu/run-times | grep vmm0 | cut -d" " -f4 ;
done`
echo "<HTML><BODY>"
echo "<TABLE width=300 border=1>"
echo "<TR><TD>VM</TD><TD>CPU</TD><TD>MEM</TD><TD>DISK</TD></TR>"
echo "<TR><TD></TD><TD>SHARES</TD><TD>SHARES</TD><TD>SHARES</TD></TR>"
echo "<TR></TR>"
 
for i in $ACTIVELIST; do
DISKSHARES=`cat /proc/vmware/vm/$i/disk/vmhba0\:0\:0| read line1; read line2; echo "$line2" | cut -d"   " -f1 ; `
CPUSHARES=`cat /proc/vmware/vm/$i/cpu/shares`
NAME=`cat /proc/vmware/vm/$i/names | cut -d\" -f6`
MEMSHARES=`cat /proc/vmware/vm/$i/mem/shares`
echo "<TR><TD>$NAME</TD><TD>$CPUSHARES</TD><TD>$MEMSHARES</TD><TD>$DISKSHARES</TD></TR>"
done


John.
Avatar of sunnycoder
sunnycoder
Flag of India image

Hi hengesystems,

DISKSHARES=`cat /proc/vmware/vm/$i/disk/vmhba0\:0\:0 | tail -1 | cut -f1`
>I would also like the script to display the current date and time at the top.
date

man date for more information

re2: Not trivial to accomplish using bash ... unless it is ok with you to use a fixed scale, e.g. print num/10 asteriks ... some other scripting language such as perl might be more convenient for this - not sure though - not much familiar with perl

Cheers!
sunnycoder
#!/usr/bin/perl
while( <DATA> ){
    if( !/\S/..0 and /\S/..0 ){
        my(@s)=split;
        push @{$c[$_]},$s[$_] for 0..$#s
    }else{
        print;
    }
}

@s=map{'*'x$_}1..@c;
@$_ = @s[sort{$_->[$a]<=>$_->[$b]} 0..$#$_] for @c[1..3];
for $i ( 0..$#{$c[0]} ){ printf"%-12s",$c[$_][$i] for 0..3; print"\n"; }
__DATA__
VM         CPU         MEM          DISK
           SHARES      SHARES       SHARES

machine1   100        3             5
machine2   200        2             15
mashine3   300        1             10
Avatar of hengesystems
hengesystems

ASKER

Hi,

Thanks for that, however

DISKSHARES=`cat /proc/vmware/vm/$i/disk/vmhba0\:0\:0 | tail -1 | cut -f1`

This didnt work.  It is displaying "      1000     163505      10465" instead of just 1000

Thanks for the Perl script, however not sure how to use it.  I created a perl file, made it executable and piped  this into it:
VM         CPU         MEM          DISK
           SHARES      SHARES       SHARES

machine1   100        3             5
machine2   200        2             15
mashine3   300        1             10

however there was no output.

Dont mind how 2 and 3 are done really, but would appreciate some more guidance here.  I just copied some of the bash script and made minor mods...  I understand even less of how the perl script works.   Is c[1..3] because there are 3 columns?

Thanks

Hi,

I played around and the following works:

DISKSHARES=`cat /proc/vmware/vm/$i/disk/vmhba0\:0\:0 | tail -1 | cut -d" " -f7`

works.

So if anyone can help me with 2 and 3 that would be great.

Thanks.
you can pipe to it like this:
perl -ne 'if( !/\S/..0 and /\S/..0 ){ my(@s)=split; push @{$c[$_]},$s[$_] for 0..$#s }else{ print} END{@$_ = map{"*"x($_+1)}sort{$_->[$a]<=>$_->[$b]} 0..$#$_ for @c[1..3]; for $i ( 0..$#{$c[0]} ){ printf"%-12s",$c[$_][$i] for 0..3; print"\n"; }}' << END
VM         CPU         MEM          DISK
           SHARES      SHARES       SHARES

machine1   100        3             5
machine2   200        2             15
mashine3   300        1             10
END

Yes, 1..3 is because there are 3 columns
it could have been 1..$#c to make it work on any number of columns
Sorry if this is a bit ignorant, can you spell it out for me.

Im not sure what perl file I need to make up and if I still need the bash script.

I have a bash script that outputs this:
VM         CPU         MEM          DISK
           SHARES      SHARES       SHARES

machine1   100        3             5
machine2   200        2             15
mashine3   300        1             10

in HTML (now working with diskshares correcytly)  and another one that has not HTML, but with spaces in between the columns.

Thanks.

Woops, also discovered that
DISKSHARES=`cat /proc/vmware/vm/$i/disk/vmhba0\:0\:0 | tail -1 | cut -d" " -f7`

only works if the first number is 1000   if it is less digits, say 300  I get a space,   I cant work out how to get cut to work with any number of spaces as delimiter.. (default of tab doesnt work, as they seem to be spaces)....  I need some other function I think.

Use

DISKSHARES=`cat /proc/vmware/vm/$i/disk/vmhba0\:0\:0 | tail -1 | tr -s " " | cut -d" " -f2`

on the command line
pipe | perl -ne 'if( !/\S/..0 and /\S/..0 ){ my(@s)=split; push @{$c[$_]},$s[$_] for 0..$#s }else{ print} END{@$_ = map{"*"x($_+1)}sort{$_->[$a]<=>$_->[$b]} 0..$#$_ for @c[1..3]; for $i ( 0..$#{$c[0]} ){ printf"%-12s",$c[$_][$i] for 0..3; print"\n"; }}'


DISKSHARES=`tail -1  /proc/vmware/vm/$i/disk/vmhba0\:0\:0 | awk '{print $1}'`
Hi ozo,

Thanks for the perl line above.  Just tested it and   I have realised that I have not been explicit enough.    I want the stars to show relative values not based on ranking, but based on total for that particular column.  

For example

VM         CPU         MEM          DISK
           SHARES      SHARES       SHARES

machine1   100        3             5
machine2   200        2             15
mashine3   300        4             100

This would come out as:

VM         CPU         MEM          DISK
           SHARES      SHARES       SHARES

machine1   *        ***          *
machine2   **      **            ***
mashine3   ***    ****        ********************


Dont know if that is possible?

By the way,  Added tail to DISKSHARES - ie
DISKSHARES=`cat /proc/vmware/vm/$i/disk/vmhba0\:0\:0 | tail -1 | awk '{print $1}'`

worked well and nice and simple.

Thankyou kindly.
> only works if the first number is 1000   if it is less digits, say 300  I get a space,

please post the result of:

   cat /proc/vmware/vm/$i/disk/vmhba0\:0\:0

(replacing $i by a valid value, for obvious reason:)
Here it is,

there are actually two lines

    shares       cmds      reads     KBread     writes  KBwritten   cmdsAbrt     busRst    paeCmds  paeCopies  splitCmds  splitCopies   issueAvg   totalAvg     active     queued          virtTime
      1000    1755525      78126     579677    1677399   17242983          0          0          0          0          0             0   42008741  128565936          0          0   520605772064329

Hope this helps.

Cheers
#!/usr/bin/perl
@max=(1)x3;
while( <> ){
    if( !/\S/..0 and /\S/..0 ){
        push @c,[split];
        for( 1..3 ){
            $max[$_]=$c[-1][$_] if $c[-1][$_]>$max[$_];
        }
     }else{
        print;
     }
}
@t=(0,3,4,20);
for$c( @c ){
    printf "%-12s"x4,$c->[0],map{'*'x(0.5+$c->[$_]*$t[$_]/$max[$_])}1..3;
    print "\n"
}
for i in $ACTIVELIST; do
  DISKSHARES=`awk '(NR==2){print $1}' /proc/vmware/vm/$i/disk/vmhba0\:0\:0`
done
Thanks ozzo!

very close,

execept the following input

VM         CPU         MEM          DISK
           SHARES      SHARES       SHARES

machine1   100        3             5
machine2   200        2             15
mashine3   300        1             10
machine4   400        4             30

outputs this:

VM         CPU         MEM          DISK
           SHARES      SHARES       SHARES

machine1    *           ***         ***
machine2    **         **           **********
mashine3    **         *             *******
machine4    ***       ****       ********************



Yet it should give this:

VM         CPU         MEM          DISK
           SHARES      SHARES       SHARES

machine1    *            ***        *
machine2    **          **          ***
mashine3    ***        *            **
machine4    ****      ****      ******


ie each column always has a single star in it.

To make it easier, you dont have to worry about fractions/rounding. The smallest number in any given column will always divide evenly into all other numbers in that column.

Thanks again for your help.  It is almost perfect


Hi Ozzo,

I am trying to work out why the second column above worked using your code, but the first column doesnt display the stars correctly.

I Played around with this line:
 $max[$_]=$c[-1][$_] if $c[-1][$_]>$max[$_];


but nothing I changed seemed to make the first column print the stars correctly.

Hope you have some ideas.  

I would like to sort this out and close this question.  

You have been a great help so far

Thanks.
ASKER CERTIFIED SOLUTION
Avatar of ozo
ozo
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Works fine on the files I gave.

Thankyou.

THink I need to learn some pear and understand how the delimiters work in your example.

as im geting division by zero errors when I feed it this:


Name     CPU    MEM    DISK
         Shares Shares Shares

DebFire2    250 500 1000
Coldfusion    1000 1400 1000
Hugo    1000 4000 1000
Peak    500 800 1000
Humans     6000 8000 8000
Spam Box    500 2000 1000
BAW    500 1000 1000

Thanks for your great help.

It is splitting on space and reading
"Spam" as the machine, "Box" as CPU, 500 as MEM and 1000 as DISK
When it tries to use "Box" as a number, it treats it as 0
That case might be better handled with something like
push @c,[/\b(.*?)\s+(\d+)\s+(\d+)\s+(\d+)/];
Fantastic.

Im making great progress now!

Just trying to get <TD> and </TD> before and after each column value.


printf"<td>%-*s"x4,10,$c->[0],map{$max[$_]/$min[$_],'*'x($c->[$_]/$min[$_])}1..3;
    print "</td>\n"
}

I can get the one at the start of each column and end of the row, but cant work out how to get one at the end of the 1st, 2nd, 3rd and 4th coumns.

Ie its looking like this now:


<td>Coldfusion  <td>****      <td>**                <td>*       </td>
<td>Hugo         <td>****       <td>********   <td>*       </td>
<td>Peak         <td>**            td>*                   <td>*       </td>
         

Once that is done, it will be complete!

printf"<td>%-*s</td>"x4
Cheers.

Working beautifully.

Thanks.