[QUIZ] Uptime Since... (#174)

M

Matthew Moss

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

The three rules of Ruby Quiz 2:

1. Please do not post any solutions or spoiler discussion for this
quiz until 48 hours have passed from the time on this message.

2. Support Ruby Quiz 2 by submitting ideas as often as you can! (A
permanent, new website is in the works for Ruby Quiz 2. Until then,
please visit the temporary website at

<http://splatbang.com/rubyquiz/>.

3. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem
helps everyone on Ruby Talk follow the discussion. Please reply to
the original quiz message, if you can.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

## Uptime Since... (#174)


Nice and easy one this week. Your task is to write a Ruby script that
reports the date and time of your last reboot, making use of the
`uptime` command.

While `uptime` is available on the various Unixes and Mac OS X,
Windows users might need to do a little extra work. Here are [two][1]
[options][2] for Windows users.


[1]: http://support.microsoft.com/kb/555737
[2]: http://articles.techrepublic.com.com/5100-10878_11-5826014.html
 
M

Matthew Moss

My own solution:


require 'date'

(now, _, dd, _, _, dhm) = `uptime`.split(/ +|,/)
(dd, dh, dm) = dd.to_i, *dhm.split(':').map { |x| x.to_i }

dh += (dm / 60.0)
dd += (dh / 24.0)

last = DateTime.parse(now) - dd

puts "Last reboot: #{last.year} #{Date::ABBR_MONTHNAMES[last.mon]}
#{last.day} at #{last.hour}:#{last.min}"
 
G

Gordon Thiesfeld

## Uptime Since... (#174)

# A windows solution.

require 'rubygems'
require 'ruby-wmi'
require 'date'

str = WMI::Win32_OperatingSystem.find:)first).LastBootupTime

boot = DateTime.strptime(str, "%Y%m%d%H%M")

boot_date = boot.strftime("%Y %b")
boot_time = boot.strftime("%I:%M")

puts "Last reboot: #{boot_date} at #{boot_time}"
 
M

Martin Bryce

And my try at this:

coeff = [60,3600]; i = 0; offset = 0
s = %x{uptime}
coeff.push 86400 if s =~ /day/

s.scan(/\d+/) do #I don't know how to stop scanning when I've had
enough ^^;;
|text|
i = i + 1
offset = offset + text.to_i*(coeff.pop||0) if (3..5) === i
end

puts (Time.now - offset).strftime("System booted at %H:%M of %A, %B %d
(%Y)")



(I don't know anything about regexp, and it shows)
 
E

Eric I.

My solution:

====

SecsPerMinute = 60
SecsPerHour = 60*SecsPerMinute
SecsPerDay = 24*SecsPerHour

match = /up (\d+) days, (\d+):(\d+),/.match %x{uptime}

# extract data from reg. exp. and convert to integers
days, hours, minutes = *((1..3).map { |index| match[index].to_i })

now = Time.now
now -= now.sec # normalize to 0 seconds into the current minute

boot_time = now - days*SecsPerDay - hours*SecsPerHour -
minutes*SecsPerMinute
boot_time_s = boot_time.strftime("%a %b %e %l:%M %p")

puts "Machine last booted: #{boot_time_s} (+/- 1 minute)."

====

Eric

====

On-site, hands-on Ruby and Ruby on Rails training is
available from http://LearnRuby.com !
 
N

Nathan Powell

Mine (Only tested on a couple of Linux boxes):


if `uptime`.include? "day"
puts(Time.now - ((`uptime`.split[2].to_i * 1440) + (`uptime`.split[4].split(":")[0].to_i * 60) + (`uptime`.split[4].split(":")[1].to_i)) * 60)
elsif `uptime`.include? "min"
puts(Time.now - `uptime`.split[2].split(":")[0].to_i * 60)
else
puts(Time.now - (`uptime`.split[2].split(":")[0].to_i * 60) + (`uptime`.split[2].split(":")[1].to_i))
end

My solution:

====

SecsPerMinute = 60
SecsPerHour = 60*SecsPerMinute
SecsPerDay = 24*SecsPerHour

match = /up (\d+) days, (\d+):(\d+),/.match %x{uptime}

# extract data from reg. exp. and convert to integers
days, hours, minutes = *((1..3).map { |index| match[index].to_i })

now = Time.now
now -= now.sec # normalize to 0 seconds into the current minute

boot_time = now - days*SecsPerDay - hours*SecsPerHour -
minutes*SecsPerMinute
boot_time_s = boot_time.strftime("%a %b %e %l:%M %p")

puts "Machine last booted: #{boot_time_s} (+/- 1 minute)."

====

Eric

====

On-site, hands-on Ruby and Ruby on Rails training is
available from http://LearnRuby.com !

--
nathan
nathan_at_nathanpowell_dot_org

To give anything less than your best is to sacrifice the gift.
~ Steve Prefontaine
------------------------------------
 
J

Jesús Gabriel y Galán

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

The three rules of Ruby Quiz 2:

1. Please do not post any solutions or spoiler discussion for this
quiz until 48 hours have passed from the time on this message.

2. Support Ruby Quiz 2 by submitting ideas as often as you can! (A
permanent, new website is in the works for Ruby Quiz 2. Until then,
please visit the temporary website at

<http://splatbang.com/rubyquiz/>.

3. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem
helps everyone on Ruby Talk follow the discussion. Please reply to
the original quiz message, if you can.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

## Uptime Since... (#174)


Nice and easy one this week. Your task is to write a Ruby script that
reports the date and time of your last reboot, making use of the
`uptime` command.

My solution, tested in Ubuntu 8.04 and Fedora Core 2:

uptime = (`uptime`.match /up (.*),.*user/)[1].delete(" ")
captures = (uptime.match /((\d+)days,)?(\d+):(\d+)/).captures[1..-1]
elapsed_seconds = captures.zip([86440, 3600, 60]).inject(0) do |total, (x,y)|
total + (x.nil? ? 0 : x.to_i * y)
end
puts "Last reboot was on #{Time.now - elapsed_seconds}"

Nice quiz !!!

Jesus.
 
J

Jesse Merriman

Here's a one-liner using /proc/uptime:

puts Time.now - File.read('/proc/uptime').match(/^(\d+\.\d+) /)[1].to_f
 
D

Daniel Berger

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

The three rules of Ruby Quiz 2:

1. Please do not post any solutions or spoiler discussion for this
quiz until 48 hours have passed from the time on this message.

2. Support Ruby Quiz 2 by submitting ideas as often as you can! (A
permanent, new website is in the works for Ruby Quiz 2. Until then,
please visit the temporary website at

<http://splatbang.com/rubyquiz/>.

3. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem
helps everyone on Ruby Talk follow the discussion. Please reply to
the original quiz message, if you can.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

## Uptime Since... (#174)

Nice and easy one this week. Your task is to write a Ruby script that
reports the date and time of your last reboot, making use of the
`uptime` command.

require 'sys/uptime'
p Sys::Uptime.uptime

Regards,

Dan

PS - No parsing involved. Uses sysctl/times/wmi, depending on platform.
 
E

Erik Hollensbe

Matthew said:
Nice and easy one this week. Your task is to write a Ruby script that
reports the date and time of your last reboot, making use of the
`uptime` command.

While `uptime` is available on the various Unixes and Mac OS X,
Windows users might need to do a little extra work. Here are [two][1]
[options][2] for Windows users.

last | grep reboot | head -1

Am I doing it right? :p

-Erik
 
M

Michael Guterl

Matthew said:
Nice and easy one this week. Your task is to write a Ruby script that
reports the date and time of your last reboot, making use of the
`uptime` command.

While `uptime` is available on the various Unixes and Mac OS X,
Windows users might need to do a little extra work. Here are [two][1]
[options][2] for Windows users.

last | grep reboot | head -1

Am I doing it right? :p

This works for me on OS X.

require 'time'
Time.parse `last | tail -1`

Michael Guterl
 
M

Matthias Reitinger

Matthew said:
Nice and easy one this week. Your task is to write a Ruby script that
reports the date and time of your last reboot, making use of the
`uptime` command.

Why use `uptime` when there's `who -b`?

Here is my solution. It should run out of the box (i.e. no gems needed)
on all major platforms.

---
require 'time'

methods = [
lambda { # Windows
require 'Win32API'
getTickCount = Win32API.new("kernel32", "GetTickCount", nil, 'L')
Time.now - getTickCount.call() / 1000.0
},
lambda { # *BSD, including Mac OS
Time.at(`sysctl -b kern.boottime 2>/dev/null`.unpack('L').first)
},
lambda { # Some other form of *nix
Time.parse(`who -b 2>/dev/null`)
}
]

begin
unless methods.empty?
boot_time = methods.shift.call
else
puts "Unable to determine time of last reboot. Sorry!"
exit!(1)
end
rescue Exception
retry
end

puts "Last reboot: #{boot_time.asctime}"
 
J

Jesús Gabriel y Galán

## Uptime Since... (#174)


Nice and easy one this week. Your task is to write a Ruby script that
reports the date and time of your last reboot, making use of the
`uptime` command.

My solution, tested in Ubuntu 8.04 and Fedora Core 2:

uptime =3D (`uptime`.match /up (.*),.*user/)[1].delete(" ")
captures =3D (uptime.match /((\d+)days,)?(\d+):(\d+)/).captures[1..-1]
elapsed_seconds =3D captures.zip([86440, 3600, 60]).inject(0) do |total, = (x,y)|
total + (x.nil? ? 0 : x.to_i * y)
end
puts "Last reboot was on #{Time.now - elapsed_seconds}"

I realized that there was a case I wasn't taking into account: a machine bo=
oted
less than 1 hour ago. So here is my revised solution, also compacting a lit=
tle
bit things, using only one regexp:

captures =3D (`uptime`.match /up (?:(?:(\d+) days,)?\s+(\d+):(\d+)|(\d+)
min)/).captures
elapsed_seconds =3D captures.zip([86440, 3600, 60, 60]).inject(0) do
|total, (x,y)|
=09total + (x.nil? ? 0 : x.to_i * y)
end
puts "Last reboot was on #{Time.now - elapsed_seconds}"

Anybody knows what's the format for a machine that's been up more than
a day, but less than two?
Is it "up 1 day" or "up 1 days"? Anyway I'm thinking changing that
part of the regexp to "day(?:s)?"
should suffice to take into account both cases, but I can't test it right n=
ow.

Jesus.
 
M

Martin Bryce

Jesús Gabriel y Galán said:
I realized that there was a case I wasn't taking into account: a machine
booted
less than 1 hour ago.

And I missed the case of an uptime between 24 and 25 hours. (On OSX, at
least). Which makes my solution fail quite badly in that time bracket.
 
F

F. Senault

Le 23 août 2008 à 16:35, Matthew Moss a écrit :

A solution tested with windows uptime.exe, FreeBSD and Linux. It should
work with most of the others and in most of the edge cases, I think.

#! /usr/local/bin/ruby

def startup(t)
u = (t.downcase.match(/up(.*?)(?:\d+ user.*)?$/)[1])
lu = u.split(/([0-9:]+)/).map { |e| e.strip.gsub(/,/, '') }.reject { |e| e == '' }
count = 0
lu.each_index do |i|
count += case lu
when /(\d+):(\d+)(?::(\d+))?/
$1.to_i * 3600 + $2.to_i * 60 + ($3 ? $3.to_i : 0)
when /(\d+)/
n = lu.to_i
case lu[i + 1]
when nil then raise "Unknown format"
when /^day/ then n * 86400
when /^hour/ then n * 3600
when /^min/ then n * 60
when /^sec/ then n
else raise "Unknown modifier (#{lu[i + 1]})"
end
else
0
end
end
Time.now - count
end

[ `uptime`,
'11:40:08 up 15 days, 16:08, 1 user,2 load average: 0.06, 0.04, 0.01',
'\\LAPHROAIG has been up for: 25 day(s), 13 hour(s), 46 minute(s), 10 second(s)'
].each { |c| puts startup(c).strftime('%c') }

12:09 fred@balvenie:~/ruby> ./uptime.rb
Wed Jun 25 07:05:41 2008
Sun Aug 10 20:01:41 2008
Thu Jul 31 22:23:31 2008

Fred
 
M

Matthias Reitinger

Jesús Gabriel y Galán said:
Anybody knows what's the format for a machine that's been up more than
a day, but less than two?
Is it "up 1 day" or "up 1 days"? Anyway I'm thinking changing that
part of the regexp to "day(?:s)?"
should suffice to take into account both cases, but I can't test it
right now.

On the machines I know (several *nixes) it is neither "up 1 day" nor "up
1 days", but "up 1 day(s)". To make matters worse some versions of
`uptime` yield a localized message:
 
E

Erik Hollensbe

Matthew said:
Because `uptime` is what I requested... :D

Sometimes it's not about the final result, but about the process.

Yep, this is a "count backwards in time" exercise slightly obfuscated.
My "solution" was a bit of a joke, and I apologize for the mess I've
caused.
 
M

Matthias Reitinger

Matthew said:
Because `uptime` is what I requested... :D

Sometimes it's not about the final result, but about the process.

I know, I know. I guess I just wanted to make my life a bit easier
there :)
 

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,769
Messages
2,569,576
Members
45,054
Latest member
LucyCarper

Latest Threads

Top