LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   shell scripting (https://www.linuxquestions.org/questions/programming-9/shell-scripting-482109/)

mitsos 09-10-2006 08:50 AM

shell scripting
 
hi
i'm trying to write a shell script that reports the amount of disks space used and available.
but when i try to add them brings an error.
Code:

df -h | grep /dev/hda1 | awk '{print $3}'
14G
df -h | grep /dev/hdb1 | awk '{print $3}'
514M

i cannot add 14G and 514M
i'm looking something that would see if the last letter is G or M
and do accordingly.

if i use
Code:

df -h | grep /dev/hda1 | awk '{print $3}' | awk -F 'G| ' ' {print $1}'
removes the G and i can add them
but what about when the disk goes to M ???

any thoughts appreciated

uselpa 09-10-2006 09:02 AM

Use df without -h, or with -k, so that the units are the same for each line.

mitsos 09-10-2006 09:17 AM

true,
but if i use it like this when i divide them i get 6,14965
how i can keep only the 6,1 or the 6,14?

thanx a lot

makyo 09-10-2006 11:46 AM

Hi, mitsos.

One way is to use a little bit of c:
Code:

#!/usr/bin/gawk -f

# @(#) a1      Demonstrate one situation of printf.

BEGIN  { n = 3.1415926 }
        { }
END    { print n
          printf("%3.2f\n",n)
        }

Running it produces:
Code:

% ./a1 /dev/null
3.14159
3.14

Change the "3.2" for width.places ... cheers, makyo

makyo 09-10-2006 12:28 PM

Hi.

There's also a stand-alone version of printf ... cheers, makyo
Code:

#!/bin/bash

# @(#) s1      Demonstrate bash builtin printf, also external on some *nix

which printf
command -V printf
pi="3.1415926"
/usr/bin/printf "%3.2f\n" $pi
command printf "%3.2f\n" $pi

Which produces:
Code:

% ./s1
/usr/bin/printf
printf is a shell builtin
3.14
3.14


naflan 09-10-2006 01:13 PM

I don't think you can do floating point calc in bash. Try Korn shell (#!/bin/ksh)

Code:

#!/bin/ksh

hda1="`df -k | grep /dev/hda1 | awk '{print $3}'`"
hda2="`df -k | grep /dev/hda2 | awk '{print $3}'`"

ktotal=$((hda1 + $hda2))
mtotal=$((ktotal / 1024.0))
gtotal=$((mtotal / 1024.0))

printf "$ktotal k used\n"
printf "%.*f M used\n" 1 $mtotal
printf "%.*f G used\n" 1 $gtotal

which on my machine produces the following results:
Code:

1270824 k used
1241.0 M used
1.2 G used


mitsos 09-10-2006 01:42 PM

thanx a lot for your replies
that helped a lot!

makyo 09-10-2006 01:46 PM

Hi, naflan.

Your ksh is better than my pdksh. I'm using "@(#)PD KSH v5.2.14 99/07/13.2" and the arithmetic didn't seem to work. I hate it when that happens. So if I'm not using awk / perl , etc., I usually end up using bc. That makes scripts more cryptic unfortunately, but the upside is that it's portable. (In the adaptation of your script, I used other disks, since I don't have an hda.) ... cheers, makyo
% cat s1
Code:

#!/bin/bash

# @(#) s1      Demonstrate calculations with bc.

disk1=hdc1
disk2=hdc3

method=ksh
method=bc

hda1="`df -k | grep /dev/$disk1 | awk '{print $3}'`"
hda2="`df -k | grep /dev/$disk2 | awk '{print $3}'`"

if [ $method = "ksh" ]
then
        echo " (Using ksh arithmetic)"
        ktotal=$(($hda1+$hda2))
        mtotal=$(($ktotal/1024.0))
        gtotal=$(($mtotal/1024.0))
else
        echo " (Using bc)"
        ktotal=$( echo "$hda1+$hda2" | bc )
        mtotal=$( echo "$ktotal/1024.0" | bc )
        gtotal=$( echo "$mtotal/1024.0" | bc )
fi

printf "$ktotal k used\n"
printf "%.*f M used\n" 1 $mtotal
printf "%.*f G used\n" 1 $gtotal
exit 0

And when run:
Code:

./s1
 (Using bc)
6320856 k used
6172.0 M used
6.0 G used


makyo 09-10-2006 03:14 PM

Hi.

I thought I had posted this, but perhaps I logged out before the final submit. My apologies if it got lost in the twisty pathways and just re-surfaced.

This uses more of the ability of awk, since that was in use earlier, and I thought it useful to show an alternative ... cheers, makyo
Code:

#!/bin/bash

# @(#) s1      Demonstrate calculations with awk.

disk1=hdc1
disk2=hdc3
disks="$disk1 $disk2"

for i in $disks
do
        df -k /dev/$i
done |
awk '
BEGIN  { sum = 0 }
/dev/  { sum += $3 }
END    { printf("%.2f k used\n", sum)
        printf("%.2f M used\n", sum / 1024)
        printf("%.2f G used\n", sum / (1024*1024))
        }'

Which then produces:
Code:

% ./s2
6320856.00 k used
6172.71 M used
6.03 G used


ghostdog74 09-10-2006 07:05 PM

Just an alternative, in Python

Code:

import statvfs
import os
st = os.statvfs("/boot")
print "preferred block size", "=>", st[statvfs.F_BSIZE]
print "fundamental block size", "=>", st[statvfs.F_FRSIZE]
print "total blocks", "=>", st[statvfs.F_BLOCKS]
print "total free blocks", "=>", st[statvfs.F_BFREE]
print "available blocks", "=>", st[statvfs.F_BAVAIL]


makyo 09-11-2006 08:53 AM

Hi, mitsos.

OK, with these versions, I hope you get the idea that there are lots of methods to solve a problem. Experimentation can be fun if you have the time to devote to it.

Some observations: I liked to see that ksh is still in use, even if I couldn't get pdksh to work as did naflan. You don't always need to use additional scripting methods if you are OK using utilities like bc and printf.

If you do employ other scripting languages, there are many to choose from. I often reach for perl, but the python that ghostdog74 posted was impressive in its brevity, and I liked that. I usually think of awk, perl, python, and shell as elderly, hackerly, orderly, and controllerly. No one posted a ruby script, but I suspect those will begin to show up in the future (and I'll need to think of a ly-word to describe that :) ).

The script below is intended to show that one can have defaults for often-used cases, but allow the flexibility of calling with different arguments. Sometimes the environment might not allow that (for example, if you need to also run code on Windows), but if it does, one can make a tool useful and general. This is clearly not the only way to do this, but it's relatively simple:
Code:

#!/bin/sh

# @(#) s4      Demonstrate calculations with awk, more general.

if [ $# -ne 0 ]
then
        partitions="$*"
else
        partitions="hdc1 hdc3"
fi

for i in $partitions
do
        echo " Looking at $i (comment out for silence)" >&2
        df -k /dev/$i
done |
awk '
BEGIN  { sum = 0 }
/dev/  { sum += $3 }
END    { printf("%.2f k used\n", sum)
        printf("%.2f M used\n", sum / 1024)
        printf("%.2f G used\n", sum / (1024*1024))
        }'

When run with no arguments:
Code:

% ./s4
 Looking at hdc1 (comment out for silence)
 Looking at hdc3 (comment out for silence)
6320856.00 k used
6172.71 M used
6.03 G used

And when run with a few SATA partitions:
Code:

% ./s4 sda6 sda7
 Looking at sda6 (comment out for silence)
 Looking at sda7 (comment out for silence)
4515732.00 k used
4409.89 M used
4.31 G used

Best wishes, and thanks to all the contributors ... cheers, makyo

AnanthaP 09-12-2006 07:42 AM

Heres `dfspace` from a shell implemetation on Solaris. It takes the thrill out of developing but is here ASIS. Note the definition of "Blksize" and "Mbyte" as an example. Note the comment. <Quote>Filesystem may be 1K bytes/block, but, df uses 512 bytes/block.<UnQuote>

end
#!/bin/sh


#ident "@(#)adm:dfspace 1.1.2.5"

#
# dfspace - d(isk) f(ree) space
# Calculate the available disk space in all mounted filesystems
# with the exception of pseudo file systems such as /proc and /dev/df.
#
# Alternately, report on filesystems/devices specified on cmd-line.
# Filesystem may be 1K bytes/block, but, df uses 512 bytes/block.
#

/bin/df -t $* | awk '
BEGIN { FS=":"; free = -1; Blksize=512; Mbyte=1048576; CONST = Blksize / Mbyte }
{
if (free == -1) { # free is toggled every other line.
split($1,fsptr,"("); FSYS=fsptr[1]
if (NF == 3) {
split($3,freeptr," "); free=freeptr[1]+0;
} else {
split($2,freeptr," "); free=freeptr[1]+0;
}
if( free == 0 && substr(freeptr[1],1,1) != "0" ) {
free = -1; next;
}
next;
}
split($2,allocptr," "); alloc = allocptr[1]+0;
if (alloc == 0) alloc = 1; # avoid division by zero
if (free >= .005)
{
TFREE= (free * CONST) - .005; # force rounding down.
}
else
{
TFREE = (free * CONST);
}
if (alloc >= .005)
{
TALLOC= (alloc * CONST) - .005; # force rounding down.
}
else
{
TALLOC = (free * CONST);
}
PCT=free * 100 / alloc;
if (TFREE <=0) TFREE=0;
if (TALLOC <=0) TALLOC=0;

if (FSYS !~ /^\/proc/ && FSYS !~ /^\/dev\/fd/)
{
if (PCT < 25.00) { printf("%c%c%c%c",27,91,49,109) };
printf ("%s: Disk space: %#6.2f MB of %#6.2f MB available (%#5.2f%%).\n", FSYS, TFREE, TALLOC, PCT);
if (PCT < 25.00) { printf("%c%c%c%c",27,91,48,109) };
}
Cumfree += free; Cumalloc += alloc;
free = -1; # reset flag/variable for next set of two lines
}
END {
if (Cumalloc > 0) {
CumPct=Cumfree * 100 / Cumalloc;
if ((Cumfree * CONST) >=.005)
{
Cumfree= (Cumfree * CONST) - .005; # force rounding down.
}
else
{
Cumfree= (Cumfree * CONST) ;
}
if ((Cumalloc * CONST) >= .005 )
{
Cumalloc= (Cumalloc * CONST) - .005; # force rounding down.
}
else
{
Cumalloc= (Cumalloc * CONST) ;
}
printf ("\nTotal Disk Space: %#6.2f MB of %#6.2f MB available (%#5.2f%%).\n", Cumfree, Cumalloc, CumPct);
}
}'

# end of disk space calculation.


All times are GMT -5. The time now is 10:44 PM.