lua - dofile, how fill stdin from lua? - lua

http://www.lua.org/manual/5.1/manual.html#pdf-dofile tells
dofile ([filename])
Opens the named file and executes its contents as a Lua chunk. When called without arguments, dofile executes the contents of the standard input (stdin). Returns all values returned by the chunk. In case of errors, dofile propagates the error to its caller (that is, dofile does not run in protected mode).
How fill stdin from lua for case when called without arguments?

If you're running a lua script or the lua interpreter in interactive mode from a command shell, calling dofile() will just get input from stdin. You'll see a blinking cursor in the shell where you can enter the lua code you want to run.
Note, running dofile in this fashion is a blocking calling, which means execution flow in your script or the lua interpreter will pause until it reads eof. Usually this means you have to enter Ctrl + Z under windows or Ctrl + D under *nix bash shell at the end.

This is an example:
-bash-4.0$ ./lua
Lua 5.3.0 (alpha) Copyright (C) 1994-2014 Lua.org, PUC-Rio
> dofile()
a = 3; print(a)
3
>
After inputting a = 3; print(a), I pressed Ctrl + D, which represents EOF on Unix. dofile() loads the input and executes it.

Related

Why Lua's builtin REPL cannot access previously delcared local vars?

See the following example:
$ lua
Lua 5.4.4 Copyright (C) 1994-2022 Lua.org, PUC-Rio
> local a = 123
> print(a)
nil
This works as expected:
> local a = 123; print(a)
123
How should I understand the behavior compared to the doc?
The scope of a local variable begins at the first statement after its declaration and lasts until the last non-void statement of the innermost block that includes the declaration.
In the Lua REPL, each (multi)line is loaded as an independent chunk via luaL_loadbuffer. The same system that makes require("mod_a") independent of require("mod_b").
Therefore, the quoted sentence still applies because every time the REPL prints a > (compared to a >> which denotes a multiline) a new block starts, thereby passing the boundary of "the last non-void statement of the innermost block".
Lua REPL treats each line of code as a separate chunk (as if it was a separate Lua file).
When a chunk execution is finished, all its local variables are lost.
So, only global variables are preserved between lines.
Lua REPL is just a REPL, it is not a debugger, where you would be able to watch and modify all variables while program is running.
To use local variables in a multi-line program in Lua REPL: start with do, enter multiple commands, and finally enter end to execute the program you entered.
$ lua
Lua 5.4.3 Copyright (C) 1994-2021 Lua.org, PUC-Rio
> do
>> local a = 123
>> print(a)
>> end
123
>

Lua io.write() adds unwanted material to output string

When I start an interactive Lua shell, io.write() adds unwanted material after the string I want it to print. print(), however does not:
[user#manjaro lua]$ lua
Lua 5.4.2 Copyright (C) 1994-2020 Lua.org, PUC-Rio
> io.write('hello world')
hello worldfile (0x7fcc979d4520)
> print('hello world')
hello world
And when I use io.write() in a program it works fine too:
--hello.lua
io.write('hello world\n')
print ('hello world')
Output:
[user#manjaro lua]$ lua hello.lua
hello world
hello world
I'm using Manjaro Linux on a Dell desktop. Can anyone tell me what's going on here? Thanks in advance.
EDIT: I should add, perhaps, that the unwanted material is always something like this:
file (0x7f346234d520)
It's always 'file' followed by what looks like a large hexadecimal number in parentheses. The exact number stays constant within one shell session but varies between different shell sessions.
"file (0x7fcc979d4520)" (or whatever address) is the return value of the io.write call, with an implicit tostring.
The lua(1) man page says
In interactive mode, lua prompts the user, reads lines from the standard input, and executes them as they are read. If the line contains an expression or list of expressions, then the line is evaluated and the results are printed.
The trouble here is that io.write('hello world') could be either an expression or a statement. Since it's a valid expression, the interpreter outputs that unwanted return value.
As a workaround, try adding a semicolon:
> io.write('hello world\n');
hello world
Although Lua usually doesn't require a semicolon for each statement if it's at the end of a line, it does allow it. And important here, it means the syntax can't be an expression, only a statement which calls the function. So the interpreter won't output the returned value.
You are just seeing the return value of io.write when you call io.write manually, interactively. When using the Lua, uh, shell, if you want to call it that, it almost always prints the return value of any function(s) you call.
file(blabblah) is the internal representation of the file you are writing to (probably just a hex memory address, but who knows?)

Input to Lua? Just like a console?

I'm trying to make a scripting tutorial for a friend (I'm not too good at it myself but okay) and I'm trying to make it so the input creates an actual line of code that does what they typed. EG:
Input: print("hello")
hello
I understand this is what a console does, but is there any way I can do it with Lua?
Thanks.
just run the lua command to get a lua "REPL":
$ ./lua
Lua 5.3.1 Copyright (C) 1994-2015 Lua.org, PUC-Rio
> print("hello")
hello
>
load
load (ld [, source [, mode [, env]]])
Loads a chunk.
If ld is a string, the chunk is this string.
...
If there are no syntactic errors, returns the compiled chunk as a function; otherwise, returns nil plus the error message.
local input = [[
local args = {...}
print(args[1], args[3]) -- 42 1
return args[1] + args[2], args[2] + args[3]
]]
print(load(input)(42, 99, 1)) -- 141 100
As you can see, the input has access to globals, you can pass values into his code and get the returns.
One way to do this would be using the loadstring function.
Example:
run = loadstring("print('Hello World!'")
run()
Output:
Hello World!

Why does the Lua REPL require you to prepend an equal sign in order to get a value?

I need help turning off this feature if possible from the interactive mode or I'm going to go mad. The REPL insists on an equal sign before every expression if you want the value. I find this very irritating and unintuitive. To make matters worse, if you mistakenly forget the equal sign, it takes you to this secondary prompt which can only be exited by
typing an expression that'll cause an error.
*** str="This is some string"
*** str
>>
>>
>> =
>>
>> =str
stdin:6: unexpected symbol near '='
*** =str
This is some string
*** #str
stdin:1: unexpected symbol near '#'
*** =#str
19
***
*** 545+8
stdin:1: unexpected symbol near '545'
*** =545+8
553
***
I need a lesson in using the REPL:
Is there a way to get rid of the equal sign so that it behaves like other REPLs?
How do you exit from the secondary prompt without doing what I did?
Everything you enter in standalone Lua is treated as a statement, as opposed to an expression. The statements are evaluated, and their results, if any, are printed to the terminal. This is why you need to prepend = (really shorthand for return) to the expressions you gave as example to get them to display properly without error.
The "secondary prompt" you are seeing is what happens when you enter an incomplete statement.
In interactive mode, if you write an incomplete statement, the interpreter waits for its completion by issuing a different prompt.
You exit from it by completing the statement.
However, it's not too difficult to make your own REPL that does what you want. Of course, you lose the ability to progressively build statements from incomplete chunks this way, but maybe you don't need that.
local function print_results(...)
-- This function takes care of nils at the end of results and such.
if select('#', ...) > 1 then
print(select(2, ...))
end
end
repeat -- REPL
io.write'> '
io.stdout:flush()
local s = io.read()
if s == 'exit' then break end
local f, err = load(s, 'stdin')
if err then -- Maybe it's an expression.
-- This is a bad hack, but it might work well enough.
f = load('return (' .. s .. ')', 'stdin')
end
if f then
print_results(pcall(f))
else
print(err)
end
until false
Since Lua 5.3, you don't need the =, because Lua first tries to interpret it as an expression now.
From the reference manual:
In interactive mode, Lua repeatedly prompts and waits for a line. After reading a line, Lua first try to interpret the line as an expression. If it succeeds, it prints its value. Otherwise, it interprets the line as a statement. If you write an incomplete statement, the interpreter waits for its completion by issuing a different prompt.
A little test:
Lua 5.3.0 Copyright (C) 1994-2014 Lua.org, PUC-Rio
> str = 'hello' .. ' Lua'
> str
hello Lua
> 1 + 2
3
>

How can I tail -F a log file(truncate aware) in 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.

Resources