I like bash(1)
, I think it's fair enough for "small" tasks. I'm often impressed with how much work it can get done in small spaces. But I think other languages can provide friendlier datastructures. A decade ago, I would have used perl(1)
for this without thinking twice but I've grown to dislike the syntax of storing hashes as values in other hashes. Python would be pretty easy too, but I know Ruby better than Python at this point, so here's something similar to what you're working on:
#!/usr/bin/ruby -w
users = Hash.new() do |hash, key|
hash[key] = Array.new()
end
lineno = 0
while(line = DATA.gets) do
lineno+=1
username, _ptr, _loc, _dow, _mon, _date, _in, _min, _out, time =
line.split()
u = users[username]
minutes = 60 * Integer(time[1..2]) + Integer(time[4..5])
u << [lineno, minutes]
end
users.each() do |user, list|
total = list.inject(0) { |sum, entry| sum + entry[1] }
puts "#{user} was on #{list.length} times for a total of #{total} minutes"
end
__END__
jww3321 pts/2 cpe-76-180-64-22 Mon Oct 18 23:29 - 00:27 (00:58)
jpd8635 pts/1 cpe-74-67-131-24 Mon Oct 18 23:22 - 03:49 (04:26)
jww3321 pts/2 cpe-76-180-64-22 Mon Oct 18 23:29 - 00:27 (00:58)
jpd8635 pts/1 cpe-74-67-131-24 Mon Oct 18 23:22 - 03:49 (04:26)
jww3321 pts/2 cpe-76-180-64-22 Mon Oct 18 23:29 - 00:27 (00:58)
jpd8635 pts/1 cpe-74-67-131-24 Mon Oct 18 23:22 - 03:49 (04:26)
The __END__
(and corresponding DATA
) are just to make this a self-contained
example. If you choose to use this, replace DATA
with STDIN
and
delete __END__
and everything following it.
Since I mostly think in C, this might not by the most idiomatic Ruby
example, but it does demonstrate how a hash (associative array) can have
an array for each key (which is sadly more complicated than it could
be), shows how to append to the array (u << ...
), shows some simple
mathematics, shows some simple iteration over the hash (users.each() do
...
), and even uses some higher order
functions (list.inject(0) { .. }
)
to calculate a sum
. Yes, the sum could be calculated with a more-usual
looping construct, but there's something about the elegence of "do this
operation on all elements of this list" that makes it an easy construct
to choose.
Of course, I don't know what you're really doing with the data from
the last(1)
command, but this ruby(1)
seems easier than the
corresponding bash(1)
script would be. (I'd like to see it, in the
end, just for my own education.)