Awk print $4 in ruby

Hi All,

I had played in Ruby a while and could not get this to work.

df -m
Filesystem 1M-blocks Used Avail Capacity Mounted on
/dev/concat/v109-v112a 7931 2619 4677 36% /

[root@vr /usr/local/vrep/OS_scripts]# df -k |awk '{print $4}'
Avail
4789776

dfstr = Array.new
dfstr << %x(df -m)
dfstr.each do |line|
    puts line if line =~ /(\d+)%/
end

Since its one line, it of course prints it all.
I then tried:

dfstr.each do |line|
    puts line.split[3]
end

And it only prints "Avail"

I then tried:

puts dfstr.scan(/Avail.*/)

and

puts dfstr.split(/\d+/)[3]

with NO success.

Goal is to get certain data columns such as Used Avail Capacity.

thank you!

···

--
Posted via http://www.ruby-forum.com/.

Derek Smith wrote:

Hi All,

I had played in Ruby a while and could not get this to work.

df -m
Filesystem 1M-blocks Used Avail Capacity Mounted on
/dev/concat/v109-v112a 7931 2619 4677 36% /

[root@vr /usr/local/vrep/OS_scripts]# df -k |awk '{print $4}'
Avail
4789776

Is this what you want ?

     df -k | ruby -lane 'print $F[3]'

···

--
Posted via http://www.ruby-forum.com/\.

Derek Smith wrote:

Hi All,

I had played in Ruby a while and could not get this to work.

df -m
Filesystem 1M-blocks Used Avail Capacity Mounted on
/dev/concat/v109-v112a 7931 2619 4677 36% /

[root@vr /usr/local/vrep/OS_scripts]# df -k |awk '{print $4}'
Avail
4789776

dfstr = Array.new

You chose a name that implies the variable is a string.
And then you make it an array.
That makes no sense.
And wouldn't it have been easier to say
dfstr =
?

dfstr << %x(df -m)

At this point in the program, add this line:

p dfstr

What does that tell you?

dfstr.each do |line|
    puts line if line =~ /(\d+)%/
end

Since its one line, it of course prints it all.
I then tried:

dfstr.each do |line|
    puts line.split[3]
end

And it only prints "Avail"

Your array contains only one string.

I then tried:

puts dfstr.scan(/Avail.*/)

and

puts dfstr.split(/\d+/)[3]

with NO success.

That means Ruby is working properly.

···

Goal is to get certain data columns such as Used Avail Capacity.

thank you!

--

Derek Smith wrote:

dfstr = Array.new
dfstr << %x(df -m)
dfstr.each do |line|
    puts line if line =~ /(\d+)%/
end

Since its one line, it of course prints it all.
I then tried:

dfstr.each do |line|
    puts line.split[3]
end

And it only prints "Avail"

You want to split the output of 'df' into lines.

Let's start with this:

   dfstr = %x(df -m)

'dfstr' now contains the complete output, as one string. You could do
'dfstr.split("\n")' to split it into lines but this isn't necessary,
because a string already has an each_line iterator:

   dfstr.each_line { |line|
      puts "a line: #{line}"
   }

So your complete program should look like:

   dfstr = %x(df -m)
   dfstr.each_line { |line|
      puts line.split[3]
   }

Now, supose you want to calculate the sum of all the totals? It's easy.
First, let's "replace" every line with its 4'th field:

   dfstr = `df -m`
   p dfstr.each_line.map { |ln| ln.split[3] }

And let's get rid of the "Available" line, and convert all strings to
numbers:

   dfstr = `df -m | tail -n +2`
   p dfstr.each_line.map { |ln| ln.split[3].to_i }

And let's sum it up:

   dfstr = `df -m | tail -n +2`
   puts "Total available space:"
   puts dfstr.each_line.map { |ln| ln.split[3].to_i }.reduce { |sum, n|
sum += n }

(BTW, You can do 'df -x tmpfs' to ommit temporary filesystems.)

···

--
Posted via http://www.ruby-forum.com/\.

dfstr = %x(df -m)
dfstr.each do |line|
  puts line.split[3]
end

Available
256227
1920
10
1920

···

On Wed, 23 Dec 2009 13:12:11 +0900, Derek Smith wrote:

Hi All,

I had played in Ruby a while and could not get this to work.

df -m
Filesystem 1M-blocks Used Avail Capacity Mounted on
/dev/concat/v109-v112a 7931 2619 4677 36% /

[root@vr /usr/local/vrep/OS_scripts]# df -k |awk '{print $4}' Avail
4789776

dfstr = Array.new
dfstr << %x(df -m)
dfstr.each do |line|
    puts line if line =~ /(\d+)%/
end

Since its one line, it of course prints it all. I then tried:

dfstr.each do |line|
    puts line.split[3]
end

And it only prints "Avail"

I then tried:

puts dfstr.scan(/Avail.*/)

and

puts dfstr.split(/\d+/)[3]

with NO success.

Goal is to get certain data columns such as Used Avail Capacity.

thank you!

--
Chanoch (Ken) Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu/~kbloom1/

(rkumar) Sentinel wrote:

Derek Smith wrote:

Hi All,

I had played in Ruby a while and could not get this to work.

df -m
Filesystem 1M-blocks Used Avail Capacity Mounted on
/dev/concat/v109-v112a 7931 2619 4677 36% /

[root@vr /usr/local/vrep/OS_scripts]# df -k |awk '{print $4}'
Avail
4789776

Is this what you want ?

     df -k | ruby -lane 'print $F[3]'

yes and no. I prefer it in script form no CLI form.

dfstr = Array.new
dfstr << %x(df -m)
dfstr.each do |line|
    ???
end

···

--
Posted via http://www.ruby-forum.com/\.

     df -k | ruby -lane 'print $F[3]'

yes and no. I prefer it in script form no CLI form.

dfstr = Array.new
dfstr << %x(df -m)
dfstr.each do |line|
    ???
end

Tried this too:

$; = 'Avail'
dfstr = %x(df -m)
puts dfstr[$;]

···

--
Posted via http://www.ruby-forum.com/\.

yes and no. I prefer it in script form no CLI form.

try this eg,

puts %x(df -m).split("\n")

Filesystem 1M-blocks Used Available Use% Mounted on
/dev/sda1 145236 99061 38856 72% /
varrun 1898 1 1898 1% /var/run
varlock 1898 0 1898 0% /var/lock
procbususb 1898 1 1898 1% /proc/bus/usb
udev 1898 1 1898 1% /dev
devshm 1898 1 1898 1% /dev/shm
gvfs-fuse-daemon 145236 99061 38856 72% /home/botp/.gvfs
=> nil

puts %x(df -m).split("\n").map{|x| x.split[3]}

Available
38856
1898
1898
1898
1898
1898
38856
=> nil

kind regards -botp

···

On Wed, Dec 23, 2009 at 10:35 PM, Derek Smith <derekbellnersmith@yahoo.com> wrote:

Derek Smith wrote:

     df -k | ruby -lane 'print $F[3]'

yes and no. I prefer it in script form no CLI form.

dfstr = Array.new
dfstr << %x(df -m)
dfstr.each do |line|
    ???
end

Tried this too:

$; = 'Avail'
dfstr = %x(df -m)
puts dfstr[$;]

I got it using, but ideally would not like to use a file on the FS.
Any comments welcome! :slight_smile:

Merry Xmas!
Thank you!

DFSTR = "/tmp/dfstr.out"
%x(df -m > "#{DFSTR}")
file = File.open("#{DFSTR}", "r")
file.each do |ln|
    ln.chomp
    fsaray =
    fsaray = ln.split
    puts fsaray[3]
end

···

--
Posted via http://www.ruby-forum.com/\.

You don't need a file, cause df will return a string with each line
separated by "\n", which the "each" method in string defaults to as a
separator:

irb(main):001:0> s = %x{df -k}
irb(main):002:0> s.each {|line| p line}
"Filesystem 1K-blocks Used Available Use% Mounted on\n"
"/dev/sda1 147549816 17405644 122649048 13% /\n"
"tmpfs 1815116 0 1815116 0% /lib/init/rw\n"
"varrun 1815116 132 1814984 1% /var/run\n"
"varlock 1815116 0 1815116 0% /var/lock\n"
"udev 1815116 2864 1812252 1% /dev\n"
"tmpfs 1815116 560 1814556 1% /dev/shm\n"
"lrm 1815116 2204 1812912 1%
/lib/modules/2.6.27-14-generic/volatile\n"

So, now, for each line, you want to split as you did and take the 4th element:
irb(main):003:0> s.map {|line| line.split[3]}
=> ["Available", "122649048", "1815116", "1814984", "1815116",
"1812252", "1814556", "1812912"]

If you want to output this array, one element in each line, you can
use puts on the full array:

irb(main):004:0> puts s.map {|line| line.split[3]}
Available
122649048
1815116
1814984
1815116
1812252
1814556
1812912

Hope this helps,

Jesus.

···

On Wed, Dec 23, 2009 at 6:06 PM, Derek Smith <derekbellnersmith@yahoo.com> wrote:

Derek Smith wrote:

 df \-k | ruby \-lane &#39;print $F\[3\]&#39;

yes and no. I prefer it in script form no CLI form.

dfstr = Array.new
dfstr << %x(df -m)
dfstr.each do |line|
???
end

Tried this too:

$; = 'Avail'
dfstr = %x(df -m)
puts dfstr[$;]

I got it using, but ideally would not like to use a file on the FS.
Any comments welcome! :slight_smile:

Merry Xmas!
Thank you!

DFSTR = "/tmp/dfstr.out"
%x(df -m > "#{DFSTR}")
file = File.open("#{DFSTR}", "r")
file.each do |ln|
ln.chomp
fsaray =
fsaray = ln.split
puts fsaray[3]
end

How about this?

IO.popen('df -h').each_line do |line|
  fsarray = line.chomp.split
  puts fsarray[3]
end

Have I missed the response mentioning the -n and -a flags to ruby?

$ df -h | ruby1.8 -na -e 'puts $F[3]'
Avail
9.0G
506M
506M
506M
506M
467M
85G
9.0G

Mike

···

On Dec 23, 2009, at 12:55 PM, Mark Thomas wrote:

How about this?

IO.popen('df -h').each_line do |line|
fsarray = line.chomp.split
puts fsarray[3]
end

--

Mike Stok <mike@stok.ca>
http://www.stok.ca/~mike/

The "`Stok' disclaimers" apply.

Mike Stok wrote:

Thanks to all who replied! :slight_smile:

I am trying to understand why my code is not entering my rundf method?

class FsData
    def initialize
        @rawdisk = @used = @available = @capacity = @filesystem = ""
        if ARGV.empty?
            puts "ARGV0 is required else script will not run"
            exit 1
        else
            @filesystem = ARGV[0]
        end
    end

    def rundf
        puts "entering rundf method"
        df = %x(df -m |tail +2)
        df.each do |ln|
            @rawdisk = ln.chomp.split[1].to_i
            @used = ln.chomp.split[2].to_i
            @available = ln.chomp.split[3].to_i
            @capacity = ln.chomp.split[4]
            @filesystem = ln.chomp.split[5]
        end
        puts @available
        if @available <= 4557
            p "#{@available} is low as testing"
        end
    end
end

p dff = FsData.new

__OUTPUT__

ruby filesys_chk.rb /
#<FsData:0x8115370 @filesystem="/", @rawdisk="", @capacity="",
@available="", @used="">

···

--
Posted via http://www.ruby-forum.com/\.

Mike Stok wrote:

Thanks to all who replied! :slight_smile:

I am trying to understand why my code is not entering my rundf method?

Well, mostly because you never tell it to. :wink:

class FsData
   def initialize
       @rawdisk = @used = @available = @capacity = @filesystem = ""
       if ARGV.empty?
           puts "ARGV0 is required else script will not run"
           exit 1
       else
           @filesystem = ARGV[0]
       end
   end

I'd suggest that this is not right for the initialize method. (Mostly because of the 'exit 1', but also because the FsData probably shouldn't refer to ARGV at all).

How about:
   def initialize(filesystem)
     @rawdisk = @used = @available = @capacity = nil
     @filesystem = filesystem
   end

   def rundf
       puts "entering rundf method"
       df = %x(df -m |tail +2)
       df.each do |ln|
           @rawdisk = ln.chomp.split[1].to_i
           @used = ln.chomp.split[2].to_i
           @available = ln.chomp.split[3].to_i
           @capacity = ln.chomp.split[4]
           @filesystem = ln.chomp.split[5]
       end
       puts @available
       if @available <= 4557
           p "#{@available} is low as testing"
       end
   end

Ooh, I'll come back to this...

end

p dff = FsData.new

if ARGV.empty?
   $stderr.puts "The filesystem is required as an argument to this script"
   exit 1
end

dff = FsData.new(ARGV[0])

dff.rundf

__OUTPUT__

ruby filesys_chk.rb /
#<FsData:0x8115370 @filesystem="/", @rawdisk="", @capacity="",
@available="", @used="">
--

OK, now back to that rundf method. I'm assuming that:
* the calls to split are OK (I think you mean to get 0..4 not 1..5, but your df output wins)
* the three fields where you use to_i need it
* you mean to get just the line for the given filesystem
* your df output doesn't have any spaces in the non-numeric fields that mess up String#split

Now, understand that the original filesystem provided is doing nothing (and is overwritten if the df.each loop runs).

   def rundf
     puts "entering rundf method"
     df = %x(df -m | tail +2)
     df.each do |ln|
       df_fields = ln.chomp.split
       next unless df_fields.last == @filesystem

       @rawdisk = df_fields[1].to_i
       @used = df_fields[2].to_i
       @available = df_fields[3].to_i
       @capacity = df_fields[4]
     end
     p "#{@available} is low as testing" if @available && @available <= 4557
     @available
   end

And perhaps a #to_s method as well:

   def to_s
     str = "#{@filesystem} :"
     str << " raw #{@rawdisk}" if @rawdisk
     str << " used #{@used}" if @used
     str << " available #{@available}" if @available
     str << " capacity #{@capacity}" if @capacity
     str
   end

I'm relying on the fact that in my version of your FsData class, the instance variables are initialized to nil (not an empty string). Others may not like the approach to building the string representation in parts in this case, but it illustrates a more general technique for when those variables might not all exist at the same time.

The end of the script could then be:
   puts FsData.new(ARGV[0])

You could also treat the whole exercise as a class method, give rundf an argument (the filesystem), and call:
   puts FsData.rundf(ARGV[0])
and not bother with an instance at all (since you don't do anything else with it).

-Rob

Rob Biedenharn http://agileconsultingllc.com
Rob@AgileConsultingLLC.com

···

On Dec 29, 2009, at 3:24 PM, Derek Smith wrote:

Rob Biedenharn wrote:
Rob@AgileConsultingLLC.com

Hi again,

Thank you Rob, quite the explanation!
I did exactly as you said and it seems my loop is not even running:

[root@vir/usr/local/vrep/OS_scripts]# ruby filesys_chk.rb /
entering to_s
#<FsData:0x8114088 @capacity=nil, @available=nil, @used=nil,
@filesystem="/", @rawdisk=nil>

class FsData
    def initialize(filesystem)
        @rawdisk = @used = @available = @capacity = nil
        @filesystem = filesystem

        if ARGV.empty?
            $stderr.puts "An argument of filesystem is required to run
this script, bye!"
            exit 1
        end
    end

    def rundf
        puts "in dfrun method"
        df = %x(df -m |tail +2)
        df.each do |ln|
            df_fields = ln.chomp.split
            next unless df_fields.last == @filesystem

            @rawdisk = df_fields[1]
            @used = df_fields[2]
            @available = df_fields[3]
            @capacity = df_fields[4]
        end
    end

    puts "entering to_s"
    def to_s
       puts "in to_s method"
       str = "#{@filesystem} :"
       str << " raw #{@rawdisk}" if @rawdisk
       str << " used #{@used}" if @used
       str << " available #{@available}" if @available
       str << " capacity #{@capacity}" if @capacity
       if @available <= 4557
           puts "YESSSSSSSSSSSSSSSSSSSSS!!!!!!!!!!"
       end
    end
end

p FsData.new(ARGV[0])

···

--
Posted via http://www.ruby-forum.com/\.

Rob Biedenharn wrote:
Rob@AgileConsultingLLC.com

Hi again,

Thank you Rob, quite the explanation!
I did exactly as you said and it seems my loop is not even running:

[root@vir/usr/local/vrep/OS_scripts]# ruby filesys_chk.rb /
entering to_s
#<FsData:0x8114088 @capacity=nil, @available=nil, @used=nil,
@filesystem="/", @rawdisk=nil>

class FsData
   def initialize(filesystem)
       @rawdisk = @used = @available = @capacity = nil
       @filesystem = filesystem

Take this test...

       if ARGV.empty?
           $stderr.puts "An argument of filesystem is required to run
this script, bye!"
           exit 1
       end

...and put it outside the class.

   end

   def rundf
       puts "in dfrun method"
       df = %x(df -m |tail +2)
       df.each do |ln|
           df_fields = ln.chomp.split
           next unless df_fields.last == @filesystem

           @rawdisk = df_fields[1]
           @used = df_fields[2]
           @available = df_fields[3]
           @capacity = df_fields[4]
       end
   end

This is begin executed during the parsing of the class definition, not when the to_s method is called. Since you already have the "in to_s method" in the right place, I'd just remove the "entering to_s" line completely.

   puts "entering to_s"
   def to_s
      puts "in to_s method"
      str = "#{@filesystem} :"
      str << " raw #{@rawdisk}" if @rawdisk
      str << " used #{@used}" if @used
      str << " available #{@available}" if @available
      str << " capacity #{@capacity}" if @capacity
      if @available <= 4557
          puts "YESSSSSSSSSSSSSSSSSSSSS!!!!!!!!!!"
      end
   end
end

p FsData.new(ARGV[0])

This creates the FsData object, but never asks it to do the rundf method.

The end of your script (i.e., following the class definition) should be:

if ARGV.empty?
   $stderr.puts "An argument of filesystem is required to run this script, bye!"
   exit 1
end

p FsData.new(ARGV[0]).rundf

Or instead of the p (perhaps better):

fs = FsData.new(ARGV[0])
fs.rundf
puts fs

You ought to get output like:

in dfrun method
in to_s method
YESSSSSSSSSSSSSSSSSSSSS!!!!!!!!!!
/ : raw 123456 used 120000 available 3456 capacity 95%

But, of course, I'm just making up the numbers.

-Rob

--
Posted via http://www.ruby-forum.com/\.

Rob Biedenharn http://agileconsultingllc.com
Rob@AgileConsultingLLC.com

···

On Dec 30, 2009, at 3:10 PM, Derek Smith wrote:

Derek Smith wrote:

        df = %x(df -m |tail +2)

On my system (Linux) "tail +2" doesn't work. You have to write it "tail
-n +2". If on your system this doesn't work, it means that this function
isn't portable and you should strip the header line via Ruby instead.

if ARGV.empty?
  $stderr.puts "An argument of filesystem is required
           to run this script, bye!"
  exit 1
end

p FsData.new(ARGV[0]).rundf

Or do:

p FsData.new(ARGV[0] || (raise "Argument not suplied")).rundf

···

--
Posted via http://www.ruby-forum.com/\.