Ruby CSV login counter script - ruby

I'm looking for a ruby script that will use something like last to count the login frequency of each user and output it to a csv file so I can make a bar graph with most frequent logins.
I want it to save the CSV output like this:
user2,19
user6,20
user3,18
Normally last looks like this:
user3 :1001 192.1.20.17 Sun Nov 30 15:01 still logged in
user8 :1000 192.1.20.15 Sun Nov 30 10:00 - 11:52 (01:52)
user2 tty7 :0 Tue Nov 25 19:43 - 21:09 (01:25)
user0 tty7 :0 Tue Nov 25 16:46 - 18:06 (01:19)
Is there something that already does this, or how can I do this?

maybe this way:
file = `last`
hash = {}
file.each_line { |x| hash[x.split(" ")[0].split(" ")[0]] = 0 unless hash[x.split(" ")[0].split(" ")[0]]; hash[x.split(" ")[0].split(" ")[0]] += 1 }
output = ""
hash.each_pair { |key, value| output += "#{key},#{value}\n" }
File.open('last.csv', 'w') {|f| f.write(output) }
you should check content of "" in split to be correct.
also you should check exact output of your last command - you maybe need to take some of the garbage out before writing to file ;)

Related

Perl's retrieval of file create time incorrect

I am attempting to use perl to rename files based on the folder they are in and the time created. Files GOPR1521.MP4 and GOPR7754.MP4 were created on two different cameras at the same time and date, and I want to be able their names to indicate that. For example .../GoProTravisL/GOPR1521.mp4 created at 12:32:38 should become 123238L_GOPR1520.mp4, and GOPR7754.MP4 becomes 123239R_GOPR7754.MP4. Right now the only problem is the time stamps. I would think its a problem with being wrong timezone or hour offset, but the minutes are off too. Is there something in perl I am missing when getting time stamps? Below is the perl code, what it outputs for times for each file, and what Finder on OS X says the creation times are.
Code:
#!/usr/bin/perl
use Time::Piece;
use File::stat;
use File::Find;
use File::Basename;
use File::Spec;
#files = <$ARGV[0]/>;
find({ wanted => \&process_file, no_chdir => 1 }, #files);
sub process_file {
my($filename, $dirs, $suffix) = fileparse($_,qr/\.[^.]*/);
if ((-f $_) && ($filename ne "" )) {
#print "\n\nThis is a file: $_";
#print "\nFile: $filename";
#print "\nDIR: $dirs";
my(#parsedirs) = File::Spec->splitdir($dirs);
my #strippeddirs;
foreach my $element ( #parsedirs ) {
push #strippeddirs, $element if defined $element and $element ne '';
}
$pardir = pop(#strippeddirs);
#print "\nParse DIR: ", $pardir;
#print "\nFile creation time: ";
$timestamp = localtime(stat($_)->ctime)->strftime("%H%M%S"); #gives time stamp
print $timestamp;
$newname = $timestamp . substr($pardir,-1) ."_". $filename . $suffix;
print "\nRename: $dirs$filename$suffix to $dirs$newname\n";
#rename ($dirs . $filename . $suffix,$dirs . $newname) || die ( "Error in renaming: " . $! );
} else {
print "\n\nThis is not file: $_\n";
}
}
Output of time stamps for each file:
/Volumes/Scratch/Raw/2016-03-21/GoProTravisL/
File: GOPR1520
File creation time: 05-55-21
File: GOPR1521
File creation time: 05-56-18
File: GOPR1522
File creation time: 05-57-44
File: GOPR1523
File creation time: 05-58-49
File: GP011520
File creation time: 05-59-53
/Volumes/Scratch/Raw/2016-03-21/GoProTravisR
File: GOPR7754
File creation time: 06-02-48
File: GOPR7755
File creation time: 06-04-19
File: GOPR7756
File creation time: 06-06-27
File: GOPR7757
File creation time: 00-06-16
File: GP017754
File creation time: 00-19-30
File: GP027754
File creation time: 00-22-20
Actual file times using ls:
MacTravis:2016-03-21 travis$ ls -lR /Volumes/Scratch/Raw/2016-03-21
total 0
drwxr-xr-x 8 travis admin 272 Apr 9 21:25 GoProTravisL
drwxr-xr-x 9 travis admin 306 Apr 9 21:25 GoProTravisR
/Volumes/Scratch/Raw/2016-03-21/GoProTravisL:
total 21347376
-rw------- 1 travis admin 4001240088 Mar 21 12:04 GOPR1520.MP4
-rw------- 1 travis admin 1447364149 Mar 21 12:31 GOPR1521.MP4
-rw------- 1 travis admin 2140532053 Mar 21 12:45 GOPR1522.MP4
-rw------- 1 travis admin 1649133454 Mar 21 13:00 GOPR1523.MP4
-rw------- 1 travis admin 1691562945 Mar 21 12:21 GP011520.MP4
/Volumes/Scratch/Raw/2016-03-21/GoProTravisR:
total 31941008
-rw------- 1 travis admin 4001129586 Mar 21 12:04 GOPR7754.MP4
-rw------- 1 travis admin 2166255754 Mar 21 12:31 GOPR7755.MP4
-rw------- 1 travis admin 3202301883 Mar 21 12:45 GOPR7756.MP4
-rw------- 1 travis admin 2466803806 Mar 21 12:08 GOPR7757.MP4
-rw------- 1 travis admin 4001257192 Mar 21 11:27 GP017754.MP4
-rw------- 1 travis admin 516025454 Mar 21 11:29 GP027754.MP4
ctime is the "time of last status change", which I believe is the time the inode was last modified. It is NOT the file's creation time[1]. ls lists the file modification time, so simply change from using ctime to using mtime.
Historically, the time at which a file was created wasn't tracked by file systems used on unix file systems. Some newer file systems track it, but I am unsure how to access it (nor is it needed here).

Why files aren't found with File.exist

I have a working directory like that one:
sascha#sascha-desktop:~/Musik/RMB/Youtube-Music$ ls -la
insgesamt 46456
drwxrwxr-x 2 sascha sascha 4096 Dez 9 10:32 .
drwxrwxr-x 3 sascha sascha 4096 Dez 6 22:47 ..
-rw-rw-r-- 1 sascha sascha 20751305 Apr 22 2015 RMB - Spring-dJl7zWZYj-E.mp4
-rw-rw-r-- 1 sascha sascha 6051641 Apr 22 2015 RMB - Spring.m4a
-rw-rw-r-- 1 sascha sascha 20751305 Apr 22 2015 RMB - Spring.mp4
In my Ruby program i'm having two methods:
def self.rename(title)
filename = title.to_s
ext = file_exist_ogg_m4a(filename)
filenamenew0 = filename.gsub(/ /, '_')
pattern = /[a-zA-Z0-9\-\s\_]/
filenamenew = filenamenew0.split(//).keep_if do |chr|
chr =~ pattern
end.join
puts 'Renaming the downloaded file'
puts "Filename: #{filename}" # debug
puts "Filenamenew: #{filenamenew}" # debug
puts "Extension: #{ext}" # debug
puts Dir.pwd # debug
#FileUtils.mv("#{filename}.#{ext}", "#{filenamenew}.#{ext}")
#[filenamenew, filename]
end
def self.file_exist_ogg_m4a(filename)
puts 'Accessing file_exist_ogg_m4a'
puts Dir.pwd # debug
if File.exist?("#{filename}.ogg")
ext = 'ogg'
elsif File.exist?("#{filename}.m4a")
ext = 'm4a'
elsif File.exist?("#{filename}.webm")
ext = 'webm'
end
puts ext # debug
puts 'Closing file_exist_ogg_m4a'
return ext # debug
end
I'm getting the extension through the file_exist_ogg_m4a method.
By running the program it gives me:
Accessing file_exist_ogg_m4a
/home/sascha/Musik/RMB/Youtube-Music
Closing file_exist_ogg_m4a
Renaming the downloaded file
Filename: RMB - Spring
Filenamenew: RMB_-_Spring
Extension:
/home/sascha/Musik/RMB/Youtube-Music
So it looks like i'm in the right directory, a #{filename}.m4a should be found, and the ext variable should contain "m4a".
But if i'm looking the running method "rename" looks me a empty #{ext}.
If i'm using that code it finds a m4a file:
dir = Dir.pwd
if !Dir.glob("#{dir}/*.ogg").empty?
ext = 'ogg'
elsif !Dir.glob("#{dir}/*.m4a").empty?
ext = 'm4a'
elsif !Dir.glob("#{dir}/*.webm").empty?
ext = 'webm'
end
So i think it has to do with the string "filename".
Maybe anyone has an idea?
File.exist? is related to the current script directory, not to the internals of Dir. One might use:
File.exist?(File.join Dir.pwd, "#{filename}.ogg")
to achieve the requested functionality.

Ruby Errno:ENOENT when filename string is a return from gsub

I'm encountering an issue with a ruby script called from CLI (not in a framework) that results in a ENOENT error (File does not exist) when attempting to open it, but only when the filename has been constructed using gsub regular expression replacement. It works when the string is constructed by any other method. I'm sure it's something simple that I've done wrong, but I've had a heck of a time figuring it out.
System Information
# lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 12.04.3 LTS
Release: 12.04
Codename: precise
# rvm -v
rvm 1.23.13 (stable) by Wayne E. Seguin <wayneeseguin#gmail.com>, Michal Papis <mpapis#gmail.com> [https://rvm.io/]
# ruby -v
ruby 2.0.0p195 (2013-05-14 revision 40734) [x86_64-linux]
Filesystem: ext2
Permissions:
# ls -lah /home/boise/config
total 24K
drwxr-xr-x 2 boise boise 4.0K Nov 13 19:40 .
drwxr-xr-x 11 boise boise 4.0K Nov 13 20:22 ..
-rwxr-xr-x 1 boise boise 248 Nov 13 09:31 boise.yaml
-rwxr-xr-x 1 boise boise 335 Nov 13 19:35 config.rb
-rwxr-xr-x 1 boise boise 339 Nov 13 20:06 stanford.yaml
-rwxr-xr-x 1 boise boise 248 Nov 13 09:49 test.yaml
user being used to run scripts and owns containing directory is 'boise'
there is nothing abnormal about the file system here, no symbolic links or
mappings or anything like that.
I started a simple script to reproduce the error. In this I boiled it down as simple as I could, made the prefix of the path static and used absolute paths so that there is no question about relative paths or current working directories.
scriptname: testing
#!/usr/bin/env ruby
require 'yaml'
# Here we are "hardcoding" the values.
$config_yaml = "boise.yaml"
puts $config_yaml
config_filespec = "/home/boise/config/#{$config_yaml}"
puts config_filespec
puts File.exists? config_filespec
$configuration = YAML.load(File.open(config_filespec))
$verbose = true
hosts = []
args = []
puts $config_yaml
ARGV.each do |arg|
if arg.match /hosts\=(.*?)/i
hosts = ARGV.delete(arg).gsub(/hosts\=(.*?)/i,'\2').split(',')
elsif arg == "quiet"
$verbose = false
ARGV.delete(arg)
elsif arg.match /cfg=(.*?)/
#Here the value of the YAML file to be loaded is set with a regular expression substitution.
$config_yaml = ARGV.delete(arg).gsub(/cfg=(.*?)/, "\2")
else
end
end
#do the same output as we did the first time hardcoded, but this time the
#value got reset by a gsub -- same variable, same name, etc
puts $config_yaml
config_filespec = "/home/boise/config/#{$config_yaml}"
puts config_filespec
puts File.exists? config_filespec
$configuration = YAML.load(File.open(config_filespec))
This works as one would expect:
# ./testing
boise.yaml
/home/boise/config/boise.yaml
true
boise.yaml
boise.yaml
/home/boise/config/boise.yaml
true
But watch what happens when I'm passing in the yaml string as a command line parameter. Note that this is even the exact same filename!
# ./testing cfg=boise.yaml
boise.yaml
/home/boise/config/boise.yaml
true
boise.yaml
boise.yaml
/home/boise/config/boise.yaml
false
./testing:31:in `initialize': No such file or directory - /home/boise/config/boise.yaml (Errno::ENOENT)
from ./testing:31:in `open'
from ./testing:31:in `<main>'
I also tried forcefully casting the string with String(config_filespec), config_filespec.to_s, and using + "" to do a string concatenation, in hopes that it was some type issue with string versus literal or regex or something like that. Any ideas?
Thanks in advance Stack Overflow!
The answer is that you're not getting the results that you think you're getting from the gsub. This boils down to a ruby quirk. When using double-quotes, "\2" evaluates to "002". However, using single quotes '\2' will return the second capture group. In your code...
$config_yaml = ARGV.delete(arg).gsub(/cfg=(.*?)/, '\2')
If you're only going to accept a single file name, would it be worth using split?
$config_yaml = ARGV.delete(arg).split(/=/, 2).last

Why does `Dir[directory_path].empty?` return `false` all the time?

Dir[directory_path].empty? returns false all the time. The behavior is the same whether or not I run irb as root:
$ ll
total 12
drwxrwxrwx 2 ndefontenay ndefontenay 4096 Aug 12 12:11 ./
drwxrwxrwx 4 ndefontenay ndefontenay 4096 Aug 5 11:45 ../
-rw-rw-r-- 1 ndefontenay ndefontenay 8 Aug 12 12:11 test
$ irb
> Dir["/opt/purge_entitlement/in"].empty?
=> false
> exit
$ sudo irb
> Dir["/opt/purge_entitlement/in"].empty?
=> false
If someone could shed some light on this problem, it would be pretty helpful.
Dir[].empty? returns false all the time
It should,because it always contains the parent directory (..), and the directory itself (.),that you didn't take care of.
This is not an answer to your question, but to avoid the problem of getting . and .. in the list, use Dir.glob instead of Dir.[]. You will probably get true for this:
Dir.glob("/opt/purge_entitlement/in/*").empty?

How to get last modified file in a directory to pass to system commands using Ruby?

I'm trying to do some dev-ops. I need to grab the last modified file in a directory to pass the filename to another command.
If I had a list of files outputted with ls -la in Ruby:
-rw-r--r-- 1 163929215 2012-11-26 00:02 appname_20121126_000002.tgz
-rw-r--r-- 1 164051752 2012-11-27 00:02 appname_20121127_000002.tgz
-rw-r--r-- 1 164160113 2012-11-28 00:02 appname_20121128_000002.tgz
-rw-r--r-- 1 164284597 2012-11-29 00:02 appname_20121129_000004.tgz
-rw-r--r-- 1 164342795 2012-11-30 00:02 appname_20121130_000003.tgz
-rw-r--r-- 1 164448312 2012-12-01 00:02 appname_20121201_000003.tgz
-rw-r--r-- 1 164490727 2012-12-02 00:02 appname_20121202_000002.tgz
-rw-r--r-- 1 164546124 2012-12-03 00:02 appname_20121203_000001.tgz
-rw-r--r-- 1 164594711 2012-12-04 00:02 appname_20121204_000002.tgz
How could I scan this with Ruby and pull the last file?
Is something like this even possible?
There's no need to shell out to ls and parse its output at all. Ruby gives you standard library methods to fetch directory contents and examine file mtimes. Here's a ruby method to return the name of a file in a directory with the latest mtime.
def last_modified_in dir
Dir.glob( File.join( dir,'*' ) ).
select {|f| File.file? f }.
sort_by {|f| File.mtime f }.
last
end
irb> system 'mkdir -p /tmp/foo'
irb> system 'rm /tmp/foo/*'
irb> ('a'..'c').each { |f| system "touch /tmp/foo/#{f}"; sleep 1; }
irb> puts last_modified_in '/tmp/foo'
# => /tmp/foo/c

Resources