How can I tail -F a log file(truncate aware) in lua? - lua

I'd like to make the output of tailf or tail -F, or something similar available to me in Lua without blocking or locking. If the file gets truncated or log rotated, the program will detect it and will return to the start. This seems to be a level 1 question but looks strange to me. I just can't figure it out. Does anyone could share some code?

Two ideas come to mind, you can just pipe the output of tail -F directly into your script execution. From there you can just read it in from stdin. Perhaps something like this:
local c = 0
for line in io.stdin:lines() do
c = c + 1
print(c, line)
end
A problem with this is that tail uses stderr to report file truncation so the script won't see it unless you find some way to redirect stderr to stdin.
The other idea is to use io.popen and force the stderr->stdin redirection before the main loop. You can then use any standard pattern matcher to check for tail truncation.
local tailin = io.popen('tail -F '..(...)..' 2>&1', 'r')
local c = 0
for line in tailin:lines() do
c = c + 1
print(c, line)
c = line:match 'truncated' and 0 or c
end
Note that both approaches are blocking btw.

Related

What's the best way to remove the last n lines of a file in a ruby script?

I'm receiving a CSV file that always includes extra lines at the end which I'd like to remove before copying the data into the postgresql database of my rails app.
I can't use head with a negative argument because I'm on MacOS X.
What's a clean and efficient way to pre-process this file?
Right now I'm doing this, but am wondering if there is less mish-mash way:
# Removes last n rows from the file located at PATH
total = `wc -c < #{PATH}`.strip.to_i
chop_index = `tail -n #{n} #{PATH} | wc -c`.strip.to_i
`dd if=/dev/null of=#{PATH} seek=1 bs=#{total - chop_index}`
This is about the simplest way I can think to do this in pure ruby that also works for large files, since it processes each line at a time instead of reading the whole file into memory:
INFILE = "input.txt"
OUTFILE = "output.txt"
total_lines = File.foreach(INFILE).inject(0) { |c, _| c+1 }
desired_lines = total_lines - 4
# open output file for writing
File.open(OUTFILE, 'w') do |outfile|
# open input file for reading
File.foreach(INFILE).with_index do |line, index|
# stop after reaching the desired line number
break if index == desired_lines
# copy lines from infile to outfile
outfile << line
end
end
However, this is about twice as slow as what you posted on a 160mb file I created. You can shave off about a third by using wc to get the total lines, and using pure Ruby for the rest:
total_lines = `wc -l < #{INFILE}`.strip.to_i
# rest of the Ruby File code
Another caveat is that your CSV must not have it's own line breaks within any cell content, in which case, you would need a CSV parser, and CSV.foreach(INFILE) do |row| could be used instead, but it is quite a bit slower in my limited testing, but you mentioned above that your cells should be ok to be processes by file line.
That said, what you posted using wc and dd is much faster, so maybe you should keep using that.

How to create a blank but valid EPS?

One of our printing applications runs an external program which does some magic and sometimes returns a barcode in EPS format to be printed on the document.
if [ ... some magic ]
then
gnu-barcode -b $1 -c -e code39 -u mm -t 1x3 > $TMP.ps
ps2epsi $TMP.ps $TMP.eps
cat $TMP.eps
rm -f $TMP.eps $TMP.ps
else
cat /dev/null
fi
This works OK. However, it generates an annoying warning on the printing application side about not receiving a valid EPS when the else ... runs and we do cat /dev/null. I need to return a blank but valid EPS instead of the cat /dev/null. How can I accomplish this?
The EPS format is defined in Adobe Technical note 5002, its available on the web but it moves around so much I won't attempt to post a URL. However, unless you are a PostScript programmer that probably won't help you.
The simplest possible valid EPS would be something like:
%!PS-Adobe-2.0 EPSF-3.0
%%BoundingBox:0 0 0 0
That's the only required content in an EPSF. Of course, a real printing application might not like a BoundingBox of 0 0 0 0.

How to make the output of Maxima cleaner?

I want to make use of Maxima as the backend to solve some computations used in my LaTeX input file.
I did the following steps.
Step 1
Download and install Maxima.
Step 2
Create a batch file named cas.bat (for example) as follows.
rem cas.bat
echo off
set PATH=%PATH%;"C:\Program Files (x86)\Maxima-5.31.2\bin"
maxima --very-quiet -r %1 > solution.tex
Save the batch in the same directory in which your input file below exists. It is just for the sake of simplicity.
Step 3
Create the input file named main.tex (for example) as follows.
% main.tex
\documentclass[preview,border=12pt,12pt]{standalone}
\usepackage{amsmath}
\def\f(#1){(#1)^2-5*(#1)+6}
\begin{document}
\section{Problem}
Evaluate $\f(x)$ for $x=\frac 1 2$.
\section{Solution}
\immediate\write18{cas "x: 1/2;tex(\f(x));"}
\input{solution}
\end{document}
Step 4
Compile the input file with pdflatex -shell-escape main and you will get a nice output as follows.
!
Step 5
Done.
Questions
Apparently the output of Maxima is as follows. I don't know how to make it cleaner.
solution.tex
1
-
2
$${{15}\over{4}}$$
false
Now, my question are
how to remove such texts?
how to obtain just \frac{15}{4} without $$...$$?
(1) To suppress output, terminate input expressions with dollar sign (i.e. $) instead of semicolon (i.e. ;).
(2) To get just the TeX-ified expression sans the environment delimiters (i.e. $$), call tex1 instead of tex. Note that tex1 returns a string, which you have to print yourself (while tex prints it for you).
Combining these ideas with the stuff you showed, I think your program could look like this:
"x: 1/2$ print(tex1(\f(x)))$"
I think you might find the Maxima mailing list helpful. I'm pretty sure there have been several attempts to create a system such as the one you describe. You can also look at the documentation.
I couldn't find any way to completely clean up Maxima's output within Maxima itself. It always echoes the input line, and always writes some whitespace after the output. The following is an example of a perl script that accomplishes the cleanup.
#!/usr/bin/perl
use strict;
my $var = $ARGV[0];
my $expr = $ARGV[1];
sub do_maxima_to_tex {
my $m = shift;
my $c = "maxima --batch-string='exptdispflag:false; print(tex1($m))\$'";
my $e = `$c`;
my #x = split(/\(%i\d+\)/,$e); # output contains stuff like (%i1)
my $f = pop #x; # remove everything before the echo of the last input
while ($f=~/\A /) {$f=~s/\A .*\n//} # remove echo of input, which may be more than one line
$f =~ s/\\\n//g; # maxima breaks latex tokens in the middle at end of line; fix this
$f =~ s/\n/ /g; # if multiple lines, get it into one line
$f =~ s/\s+\Z//; # get rid of final whitespace
return $f;
}
my $e1 = do_maxima_to_tex("diff($expr,$var,1)");
my $e2 = do_maxima_to_tex("diff($expr,$var,2)");
print <<TEX;
The first derivative is \$$e1\$. Differentiating a second time,
we get \$$e2\$.
TEX
If you name this script a.pl, then doing
a.pl z 3*z^4
outputs this:
The first derivative is $12\,z^3$. Differentiating a second time,
we get $36\,z^2$.
For the OP's application, a script like this one could be what is invoked by the write18 in the latex file.
If you really want to use LaTeX then the maxiplot package is the answer. It provides a maxima environment inside of which you enter Maxima commands. When you process your LaTeX file a Maxima batch file is generated. Process this file with Maxima and process your LaTeX file again to typeset the equations generated by Maxima.
If you would rather have 2D math input with live typesetting then use TeXmacs. It is a cross-platform document authoring environment (a word processor on steroids if you like) that includes plugins for Maxima, Mathematica and many more scientific computing tools. If you need to or are not satisfied with the typesetting, you can export your document to LaTeX.
I know this is a very old post. Excellent answers for the question asked by OP. I was using --very-quiet -r options on the command line for a long time like OP, but in maxima version 5.43.2 they behave differently. See maxima command line v5.43 is behaving differently than v5.41. I am answering this question with a cross reference because when incorporating these answers in your solutions, make sure the changes in behavior of those command line flags are also incorporated.

Lua print on the same line

In Pascal, I have write and writeln. Apparently Lua's print is similar to writeln of Pascal. Do we have something similar to write of Pascal? How can consecutive print commands send their output to the same line?
print("Hello")
print("World")
Output:
Hello
world
I want to have this:
Hello world
Use io.write instead print, which is meant for simple uses, like debugging, anyway.
Expanding on lhf's correct answer, the io library is preferred for production use.
The print function in the base library is implemented as a primitive capability. It allows for quick and dirty scripts that compute something and print an answer, with little control over its presentation. Its principle benefits are that it coerces all arguments to string and that it separates each argument in the output with tabs and supplies a newline.
Those advantages quickly become defects when detailed control of the output is required. For that, you really need to use io.write. If you mix print and io.write in the same program, you might trip over another defect. print uses the C stdout file handle explicitly. This means that if you use io.output to change the output file handle, io.write will do what you expect but print won't.
A good compromise can be to implement a replacement for print in terms of io.write. It could look as simple as this untested sample where I've tried to write clearly rather than optimally and still handle nil arguments "correctly":
local write = io.write
function print(...)
local n = select("#",...)
for i = 1,n do
local v = tostring(select(i,...))
write(v)
if i~=n then write'\t' end
end
write'\n'
end
Once you are implementing your own version of print, then it can be tempting to improve it in other ways for your application. Using something with more formatting control than offered by tostring() is one good idea. Another is considering a separator other than a tab character.
As an alternative, just build up your string then write it out with a single print
You may not always have access to the io library.
You could use variables for "Hello" and "World". Then concatenate them later. Like this:
local h = "Hello"
local w = "World"
print(h..w)
It will be display, in this case, as "HelloWorld". But that's easy to fix. Hope this helped!
Adding on to #Searous's answer, try the following.
local h = "hello"
local w = "world"
print(h.." "..w)
You can concatenate both together, just concatenate a space between both variables.
local h = "Hello"
local w = "World!"
print(h, w)

How to prevent Maxima tex1 from wrapping its output?

I invoked Maxima tex1 from within a batch script as follows:
maxima --very-quiet -r "tex1(solve(8*x^2+7*x+5));" | grep -v false > output.txt
and I got the output.txt as follows:
\left[ x=-{{\sqrt{111}\,i+7}\over{16}} , x={{\sqrt{111}\,i-7}\over{16}} \righ\
t]
that is not valid as a (La)TeX input file.
How to prevent Maxima tex1 from wrapping its output?
Sorry for the late reply.
Instead of
tex1(solve(8*x^2+7*x+5));
write:
?princ(tex1(solve(8*x^2+7*x+5)))$
The problem is that the string returned by tex1 is being printed by the display formatter (the same function which would print the string if you were using Maxima in an interactive session). The display formatter breaks strings at linel characters (default = 79) and inserts a backslash. Instead for your purposes you want to evade the display formatter entirely, so you print the string with ?princ (a Lisp function to just print the string) and terminate the input with "$" instead of ";" to tell Maxima not to call the display formatter.
Note that the hard-coded constant 70 in MYPRINC doesn't come into play here. MYPRINC is not called in the example given.
This is, unfortunately, hard coded into Maxima. A way to solve this problem is to edit the function myprinc located in the file maxima/src/mactex.lisp. There is a cond form that has a 70. written there, it should read linel instead of 70. If you recompile maxima after making this change then the following will work:
maxima --very-quiet -r "linel: 1000$ tex1(solve(8*x^2+7*x+5));" | grep -v false > output.txt
Anyway, I'll send a patch to the Maxima list ASAP so that future versions of the program won't have this shortcoming.

Resources