awk print $4 in ruby

D

Derek Smith

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!
 
W

W. James

Derek said:
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!



--
 
R

(rkumar) Sentinel

Derek said:
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]'
 
D

Derek Smith

(rkumar) Sentinel said:
Derek said:
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
 
D

Derek Smith

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[$;]
 
B

botp

yes and no. =A0I prefer it in script form no CLI form.

try this eg,
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
=3D> nil
puts %x(df -m).split("\n").map{|x| x.split[3]}
Available
38856
1898
1898
1898
1898
1898
38856
=3D> nil

kind regards -botp
 
D

Derek Smith

Derek said:
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! :)

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
 
J

Jesús Gabriel y Galán

Derek said:
=A0 =A0 =A0df -k | ruby -lane 'print $F[3]'

yes and no. =A0I prefer it in script form no CLI form.

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

Tried this too:

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

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

Merry Xmas!
Thank you!


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

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 =3D %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 eleme=
nt:
irb(main):003:0> s.map {|line| line.split[3]}
=3D> ["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.
 
M

Mark Thomas

How about this?

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

Albert Schlef

Derek said:
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.)
 
K

Ken Bloom

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!

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

Available
256227
1920
10
1920
 
D

Derek Smith

Mike Stok wrote:

Thanks to all who replied! :)

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="">
 
R

Rob Biedenharn

Thanks to all who replied! :)

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

Well, mostly because you never tell it to. ;-)
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
(e-mail address removed)
 
D

Derek Smith

Rob said:
(e-mail address removed)

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])
 
R

Rob Biedenharn

Rob Biedenharn wrote:
(e-mail address removed)

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

Rob Biedenharn http://agileconsultingllc.com
(e-mail address removed)
 
A

Albert Schlef

Derek said:
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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,200
Latest member
LaraHunley

Latest Threads

Top