Uptime Since... (#174)

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

The three rules of Ruby Q. 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 Q. 2 by submitting ideas as often as you can! (A
    permanent, new website is in the works for Ruby Q. 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 T. 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
options for Windows users.

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}”

On Sat, Aug 23, 2008 at 9:35 AM, Matthew M. [email protected]
wrote:

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}”

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)

My solution:

====

SecsPerMinute = 60
SecsPerHour = 60SecsPerMinute
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 - daysSecsPerDay - hoursSecsPerHour -
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 !

On Sat, Aug 23, 2008 at 4:35 PM, Matthew M. [email protected]
wrote:

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.

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

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

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

On Tue, Aug 26, 2008 at 01:30:50AM +0900, Eric I. wrote:

extract data from reg. exp. and convert to integers

====

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

On Aug 23, 8:35 am, “Matthew M.” [email protected] wrote:

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

:slight_smile:

Regards,

Dan

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

Nathan Powell wrote:

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

I may be wrong, but won’t the results from this be skewed because you
are
running uptime several times (and presumably the resulting data will be
different each time you run it)?

It’s not like that couldn’t be fixed very easily by just assigning a
variable.
Nice solution, though!

-Dana

Matthew M. wrote:

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? :stuck_out_tongue:

-Erik

Matthew M. wrote:

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}”

Regards,
Matthias

On Mon, Aug 25, 2008 at 6:12 PM, Erik H. [email protected]
wrote:

last | grep reboot | head -1

Am I doing it right? :stuck_out_tongue:

This works for me on OS X.

require ‘time’
Time.parse last | tail -1

Michael G.

Jesús Gabriel y Galán wrote:

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.

On Mon, Aug 25, 2008 at 7:30 PM, Jesús Gabriel y
Galán[email protected] wrote:

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}”

I realized that there was a case I wasn’t taking into account: a machine
booted
less than 1 hour ago. So here is my revised solution, also compacting a
little
bit things, using only one regexp:

captures = (uptime.match /up (?:(?:(\d+) days,)?\s+(\d+):(\d+)|(\d+)
min)/).captures
elapsed_seconds = captures.zip([86440, 3600, 60, 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}”

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.

Jesus.

Le 23 août 2008 à 16:35, Matthew M. 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[i]
when /(\d+):(\d+)(?::(\d+))?/
$1.to_i * 3600 + $2.to_i * 60 + ($3 ? $3.to_i : 0)
when /(\d+)/
n = lu[i].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©.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

Jesús Gabriel y Galán wrote:

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:


1:49pm in Betrieb 6 Tag(e), 9:12, 12 Benutzer, Durchschnittslast:
3,11, 3,13, 3,19

Maybe a more general approach is needed to account for these corner
cases.

Matthew M. wrote:

On Aug 25, 11:20�pm, Matthias R. [email protected] wrote:

Matthew M. wrote:

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?

Because uptime is what I requested… :smiley:

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.

On Aug 25, 11:20 pm, Matthias R. [email protected] wrote:

Matthew M. wrote:

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?

Because uptime is what I requested… :smiley:

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

On Aug 26, 10:44 am, Matthias R. [email protected] wrote:

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 :slight_smile:

No worries. I’m not deducting any points this week. :wink: