tags:

views:

27

answers:

2

I'm definitely interested in getting a book on awk. I've been won over, despite playing with it for little time. However, in the mean time, I have a problem I suspect I could solve exclusively with [g]awk. To demonstrate, I'll use some fdisk output. In this example, the desired end result would be something like:

Disks: 2 [240 GB total]
sda=120 GB
sdb=120 GB

Here's what I have:

fdisk -l 2>/dev/null | awk '/^Disk \/dev\/[vsh]d./ {bytes+=$5} END {print "Disks: "NR" ["; gb=bytes/1024/1024/1024; print gb" GB total]"}'

My NR apparently prints out 73.. on my laptop with two hard drives, anyway. This, I do not understand. So far, well.. I'm maybe half-way there. Any tips or succinct tutorials would be greatly appreciated!


After two major excellent answers, I ended up with the following:

echo DISKS: $(fdisk -l 2>/dev/null | awk -F/ '/^Disk \/dev\/[vsh]d.|^Disk \/dev\/xvd./{print$3}' | awk '{d++;bytes+=$4;disk[$1]=$2" "$3}END{gb=bytes/1024/1024/1024; printf gb" GB total, "d" disks\n";for (i in disk) print "  "i,disk[i]}' | sed -e "s/,$/ /" -e "s/: / /")

Which gave me output like this:

DISKS: 78.3585 GB total, 2 disks
  sda 80.0 GB
  sdb 4110 MB

Looking forward to the day I can do that all in one awk command with no sed. :) But for now, thanks folks!

A: 

You're more than half way. The only issue is that NR is the number of rows (so far), not the number of rows matching your expression. So just use another variable for that.

fdisk -l 2>/dev/null | awk '/^Disk \/dev\/[vsh]d./ {bytes+=$5; disks+=1} END {print "Disks: "disks" ["; gb=bytes/1024/1024/1024; print gb" GB total]"}'

That gives:

Disks: x [
yyy GB total]

To remove the newline, and add output for each drive, try:

fdisk -l 2>/dev/null | awk '/^Disk \/dev\/[vsh]d./ {cur_bytes=$5; bytes+=cur_bytes; disks+=1; gsub(/dev|:|\//, "", $2); print $2 "=" cur_bytes/1024/1024/1024 " GB";} END {printf "Disks: "disks" ["; gb=bytes/1024/1024/1024; print gb" GB total]"}'

That gives:

sda=xx GB
sdb=yy GB
sdc=zz GB
Disks: 3 [ww GB total]

It doesn't print the header first. You could use concatenation to do that.

Matthew Flaschen
Or to simplify the last part: `END {print "Disks: " disks " [" gb=bytes/1024/1024/1024 " GB total]"}'`. The only reason I can see using a variable is if you wanted to move the calculation before the `print` statement to simplify its appearance. Even then, you would only need one `print`. `END {gb = bytes/1024/1024/1024; print "Disks: " disks " [" gb " GB total]"}'`
Dennis Williamson
@Dennis, that's fine, except you have to remove `gb=` from the first one.
Matthew Flaschen
Oops [ ](http://google.com)
Dennis Williamson
@Matthew, Dennis: Thanks for responding so quickly when I posted this! I've been very busy for the last week, but I saw the answers immediately. Twas very helpful.
ryran
+1  A: 
$ fdisk -l 2>/dev/null | awk '/^Disk \/dev\/[vsh]d./{d++;bytes+=$5;disk[$2]=$3$4} END {printf "Disks: "d" ["; gb=bytes/1024/1024/1024; printf gb" GB total]\n";for (i in disk) print i,disk[i]}'
Disks: 1 [93.1604 GB total]
/dev/sda: 100.0GB,
ghostdog74
I appreciate it ghostdog74! Your example was just what I was looking for. It opens up some new possibilities with awk.
ryran