grep logs for the last X minutes every X minutes - grep

I want to grep logs for the last X minutes every X minutes(ex: grep logs of last 5 min every 5 min) without grep-ing anything older. What could be the simplest way to do this?

A Ruby 1.9.3 solution
The second part that you require, I haven't tested it yet :(
Note: Also if you know the location of 'ruby' change the shebang (first line of the script),
for security reasons.
#! /usr/bin/env ruby
require 'date'
require 'pathname'
if ARGV.length != 4
$stderr.print "usage: #{$0} -d|-h|-m|-s time expression log_file\n"
exit 1
end
begin
total_amount = Integer ARGV[1]
rescue ArgumentError
$stderr.print "error: parameter 'time' must be an Integer\n"
$stderr.print "usage: #{$0} -d|-h|-m|-s time expression log_file\n"
end
if ARGV[0] == "-m"
gap = Rational(60, 86400)
time_str = "%b %d %H:%M"
until_next_search = total_amount * 60
elsif ARGV[0] == "-s"
gap = Rational(1, 86400)
time_str = "%b %d %H:%M:%S"
until_next_search = total_amount
elsif ARGV[0] == "-h"
gap = Rational(3600, 86400)
time_str = "%b %d %H"
until_next_search = total_amount * 3600
elsif ARGV[0] == "-d"
time_str = "%b %d"
gap = 1
until_next_search = total_amount * 86400
else
$stderr.print "usage: #{$0} -d|-h|-m|-s time expression log_file\n"
exit 1
end
pn = Pathname.new(ARGV[3])
if pn.exist?
log = (pn.directory?) ? ARGV[3] + "/*" : ARGV[3]
else
$stderr.print "error: file '" << ARGV[3] << "' does not exist\n"
$stderr.print "usage: #{$0} -d|-h|-m|-s time expression log_file\n"
end
search_str = ARGV[2]
now = DateTime.now
while true
total_amount.times do
now -= gap
system "cat " << log << " | grep '" << now.strftime(time_str) << ".*" << search_str << "'"
end
sleep until_next_search
end

Related

field separator in awk

I have the following "input.file":
10 61694 rs546443136 T G . PASS RefPanelAF=0.0288539;AC=0;AN=1186;INFO=1.24991e-09 GT:DS:GP 0/0:0.1:0.9025,0.095,0.0025 0/0:0.1:0.9025,0.095,0.0025 0/0:0.1:0.9025,0.095,0.0025
My desired output.file is:
0.1, 0.1, 0.1
Using an awk script called "parse.awk":
BEGIN {FS = ":"}
{for (i = 4; i <= NF; i += 2) printf ("%s%c", $i, i +2 <= NF ? "," : "\n ");}
which is invocated with:
awk -f parse.awk <input.file >output.file
my current output.file is as follows:
0.1,0.1,0.1
i.e. no spaces.
Changing pasre.awk to:
BEGIN {FS = ":"}
{for (i = 4; i <= NF; i += 2) printf ("%s%c", $i, i +2 <= NF ? ", " : "\n ");}
did not change the output.file. What change(s) to parse.awk will yield the desired output.file?
You may use this awk:
awk -F: -v OFS=', ' '{
for (i = 4; i <= NF; i += 2) printf "%s%s", $i, (i < NF-1 ? OFS : ORS)}' file
0.1, 0.1, 0.1
Could you please try following. Written and tested it in
https://ideone.com/e26q7u
awk '
BEGIN {FS = ":"}
val!=""{ print val; val=""}
{for (i = 4; i <= NF; i += 2){
val=(val==""?"":val", ")$i
}
}
END{
if(val!=""){
print val
}
}
' Input_file
The problem is when you changed the output separator from a single comma (",") to comma with space (", "); you did not change the format string from %c to %s. So that is how to fix your script:
BEGIN {FS = ":"}
{for (i = 4; i <= NF; i += 2) printf ("%s%s", $i, i +2 <= NF ? ", " : "\n ");}
# ^ Change this

Start second while loop only after first is finished

I'm trying to write a function that puts the remaining seconds into a human readable format. The problem I'm having(I think) is that my second while loop is trying to do it's job before the first is finished. I'll end up with "1 hour, 271 minutes and 37 seconds. In my latest attempt, I tried to use minNeeded but that doesn't work either because it's checking for it's existence prior to the first loop being finished. How can I manage this?
function prettyTime(secs)
local hr = 0
local hrDisplay = ''
local min = 0
local minDislplay = ''
local minNeeded = 0
if(secs >= 3600) then
while secs >= 3600 do
secs = secs - 3600
hr = hr + 1
if secs < 3600 then
secsRemaining = secs
minNeeded = 1
end
end
else
minNeeded = 1
end
while true do
if(minNeeded == 1){
while secsRemaining >= 60 do
secsRemaining = secsRemaining - 60
min = min + 1
end
end
end
if hr > 1 then
hrDisplay = hr .. ' hours, '
elseif hr == 1 then
hrDisplay = '1 hour, '
end
if min > 1 then
minDisplay = min .. ' minutes and '
elseif min == 1 then
minDisplay = '1 minute and '
else
minDisplay = ''
end
return hrDisplay .. minDisplay .. secs .. ' seconds'
end
your Code has few bugs, if(minNeeded == 1){ is syntax error, while true do will never break.
Here is the simple converter,
function prettyTime(sec)
local sec = tonumber(sec)
if sec <= 0 then
return "00.00.00";
else
h = tonumber(string.format("%02.f", math.floor(sec/3600)))
m = tonumber(string.format("%02.f", math.floor(sec/60 - (h*60))))
s = tonumber(string.format("%02.f", math.floor(sec - h*3600 - m*60)))
-- return h.."."..m.."."..s
end
local res = ''
if h == 1 then
res = res ..h .. ' hour, '
elseif h > 1 then
res = res ..h .. ' hours, '
end
if m <= 1 then
res = res ..m .. ' minute, '
elseif m > 1 then
res = res ..m .. ' minute, '
end
if s <= 1 then
res = res ..s .. ' second, '
elseif s > 1 then
res = res ..s .. ' seconds '
end
return res
end
print(prettyTime(3670)) -- 1 hour, 1 minute, 10 seconds

convert data formatting in a lua file

hello i need to convert 720 data sets from a 1 liner to this format below.
Atm i got them in a open office file with each number in a column but i have no idea how i can convert that formatting.
12 -8906.071289 560.890564 93.236107 0 test2
13 -846.814636 -526.218323 10.981694 0 southshore
to
[12] = {
[1] = "test2",
[2] = "-8906.071289",
[3] = "560.890564",
[4] = "93.236107",
[5] = "0",
},
[13] = {
[1] = "Southshore",
[2] = "-846.814636",
[3] = "-526.218323",
[4] = "10.981694",
[5] = "0",
},
One possibility in Lua. Run with program.lua datafile
where program.lua is whatever name you give this file, and datafile is, well, your external data file. Test with just program.lua
--[[
12 -8906.071289 560.890564 93.236107 0 test2
13 -846.814636 -526.218323 10.981694 0 southshore
--]]
local filename = arg[1] or arg[0] --data from 1st command line argument or this file
local index,head,tail
print '{'
for line in io.lines(filename) do
if line:match '^%d+' then
head, line, tail = line:match '^(%d+)%s+(.-)(%S+)$'
print(' [' .. head .. '] = {\n [1] = "' .. tail .. '",')
index = 1
for line in line:gmatch '%S+' do
index = index + 1
print(' [' .. index .. '] = "' .. line .. '",')
end
print ' },'
end
end
print '}'
This awk program does it:
{
print "[" $1 "] = {"
print "\t[" 1 "] = \"" $NF "\","
for (i=2; i<NF; i++) {
print "\t[" i "] = \"" $i "\","
}
print "},"
}

How do you reference a table with a key value that is numeric in Lua?

The output for the below script is:
AD[1] = [variable not found]
AD['2'] = bar
How can I modify the function getfield to return a value for v for both cases?
function getfield (f)
local v = _G
for w in string.gfind(f, "[%w_]+") do
v = v[w]
end
return v
end
AD = {[1] = 'foo', ['2'] = 'bar'}
data = {"AD[1]","AD['2']"}
for i,line in ipairs(data) do
s = getfield(line)
if s then
print(line .. " = " .. s)
else
print(line .. " = [variable not found]")
end
end
UPDATE:
I'm 90% sure, this is going to work for me:
function getfield (f)
local v = _G
for w in string.gfind(f, "['%w_]+") do
if (string.find(w,"['%a_]")==nil) then
w = loadstring('return '..w)()
else
w = string.gsub(w, "'", "")
end
v=v[w]
end
return v
end
This happens to work
function getfield (f)
local v = _G
for w in string.gfind(f, "['%w_]+") do
local x = loadstring('return '..w)()
print(w,x)
v = v[x] or v[w]
end
return v
end
AD = {[1] = 'foo', ['2'] = 'bar'}
data = {"AD[1]","AD['2']"}
for i,line in ipairs(data) do
s = getfield(line)
if s then
print(line .. " = " .. s)
else
print(line .. " = [variable not found]")
end
end
but it's pretty fragile.
Note that I added ' to the pattern.
The difficulty is that sometimes w is a string representing a name (key), and sometimes it's a string representing a number. In the second case it needs to be converted from string to number. But you need the context or some syntax to decide.
Here's the kind of fragility I mean:
> data = {"math[pi]","AD['2']"}
>
> for i,line in ipairs(data) do
>> s = getfield(line)
>> if s then
>> print(line .. " = " .. s)
>> else
>> print(line .. " = [variable not found]")
>> end
>> end
math table: 0x10ee05100
pi nil
math[pi] = 3.1415926535898
AD table: 0x10ee19ee0
'2' 2
AD['2'] = bar
> pi = 3
> math[3] = 42
> data = {"math[pi]","AD['2']"}>
> for i,line in ipairs(data) do
>> s = getfield(line)
>> if s then
>> print(line .. " = " .. s)
>> else
>> print(line .. " = [variable not found]")
>> end
>> end
math table: 0x10ee05100
pi 3
math[pi] = 42
AD table: 0x10ee19ee0
'2' 2
AD['2'] = bar
math[pi] is unchanged, but getfield interprets pi in the global context and gets 3 so the wrong field of math is returned.
You'll get the strings '1' and "'2'". You have to evaluate it to turn it into whatever object it is:
v = v[loadstring('return ' .. w)()]
Don't do this if the string came from an untrusted source though (like a user input or something) because they could execute arbitrary code.

How to monitor progress from ffmpeg?

I have this ffmpeg video encoder using Rails and I needed to report ffmpeg progress to the user.
How can that be done provided that I am using Linux?
This is the solution I reached:
def execute_ffmpeg(cmd, progress)
logger.debug "Running command #{cmd}"
command = "#{cmd} 2>&1"
progress = nil
frames = nil
fps = 25
ffmpeg = IO.popen(command)
ffmpeg.each("\r") do |line|
if frames.nil? && line =~ /Duration:(\s.?(\d*):(\d*):(\d*\.\d*))/
duration = $2.to_s + ":" + $3.to_s + ":" + $4.to_s
frames = ($4.to_i + ($3.to_i * 60) + ($2.to_i * 60 * 60)) * fps
end
if line =~ /frame=(\s.?(\d*))/
progress = $1.to_i / frames.to_i
print "Progress: #{progress}"
end
end
end
Thanks for the post, I modified it a little. I am using ffmpeg version 0.10.2. Here's my version:
def exec_ffmpeg src_path, dst_path
cmd = "ffmpeg -i \"%s\" -acodec libfaac -ac 2 -ab 128k -vcodec libx264 -threads 0 \"%s\" 2>&1" %
[src_path, dst_path]
puts "%s" % cmd.gsub(/2\>\&1$/,'')
puts "press 'q' to quit"
progress = nil
dur_secs = nil
frame_rate = nil
frames = 0
dur_str = '00:00:00.000'
ostr = ''
ffmpeg = IO.popen(cmd)
ffmpeg.each("\r") do |line|
if dur_secs == nil && line =~ /Duration:\s*(\d*):(\d*):(\d*\.\d*)/
dur_str = $1.to_s + ":" + $2.to_s + ":" + $3.to_s
dur_secs = ($3.to_f + ($2.to_i * 60).to_f + ($1.to_i * 360).to_f)
puts "Video Duration:" + dur_str
end
if frame_rate == nil && line =~ /Stream.+\, (\d+\.{0,1}\d{0,3}) fps\,/
frame_rate = $1.to_f
frames = dur_secs * frame_rate
puts "Total Frames: %i" % frames.to_i
puts "Frame Rate: %.3f fps" % frame_rate
end
if line =~ /frame=(\s.?(\d*))/
cframe = $1.to_i
csecs = 0
if line =~ /time=\s*(\d*):(\d*):(\d*\.\d*)/
csecs = ($3.to_f + ($2.to_i * 60).to_f + ($1.to_i * 360).to_f)
csecs_str = $1.to_s + ":" + $2.to_s + ":" + $3.to_s
elsif line =~ /time=\s*(\d*\.\d*)/
csecs $1.to_f
t = Time.at(csecs).gmtime
csecs_str = "%0.2i:%0.2i:%0.2i.%3i" % [t.hour, t.min, t.sec, t.nsec]
end
if line =~ /fps=\s*(\d*)/
cfps = $1.to_i
else
cfps = 0
end
if line =~ /bitrate=\s*(\d*\.\d*kbits)/
br = $1
else
br = "???"
end
ostr = " %3.2f%% ( %s ) #frame:%i fps:%i bitrate:%s" %
[((csecs/dur_secs)*100), csecs_str, cframe, cfps, br]
print ostr + ("\b" * (ostr.length + 4))
end
end
print "\n"
end

Resources