Say I call Lua with this cmd:
luajit neuralnetwork.lua --satEpoch "somestring" --maxEpoch 50
How can I access this same cmd-line string from Lua?
I know about the arg table, but it removes all quotes from the original command string making it difficult to reconstruct:
{
"--maxEpoch"
"--satEpoch"
"50"
"somestring"
[-1] : "luajit"
[0] : "examples/neuralnetwork.lua"
}
If I can save the exact string to a file from within Lua, I can easily call it again later.
#peterpi is correct that the shell is interpreting the command and as a result stripping away the quotes. However, reconstructing the command exactly is not really necessary to have the shell interpret the command the same way as before.
For simple cases concatenating the arguments to the script is often enough:
local command = table.concat(arg, ' ', -1, #arg)
This will fail if the quotes are actually necessary, most commonly when an argument contains a space or shell character, so quoting everything is easy and somewhat more robust, but not pretty.
Here is an example with a Lua pattern to check for special (bash) shell characters and spaces to decide if and which quotes are necessary. It may not be complete but it handles filenames, most strings, and numbers as arguments.
local mod_arg = { }
for k, v in pairs(arg) do
if v:find"'" then
mod_arg[k] = '"'..v..'"'
elseif v:find'[%s$`><|#]' then
mod_arg[k] = "'"..v.."'"
else
mod_arg[k] = v
end
end
local command = table.concat(mod_arg, ' ', -1, #mod_arg)
print(command)
No doubt somebody will prove me wrong, but generally I don't think this is possible. It's the shell rather than luajit that takes the quotes away and chops the line up into individual tokens.
Related
I want to convert this python code to lua .
for i in range(1000,9999):
if str(i).endswith('9'):
print(i)
I've come this far ,,
for var=1000,9000 then
if tostring(var).endswith('9') then
print (var)
end
end
but I don't know what's the lua equivalent of endswith() is ,,, im writing an nmap script,,
working 1st time with lua so pls let me know if there are any errors ,, on my current code .
The python code is not great, you can get the last digit by using modulo %
# python code using modulo
for i in range(1000,9999):
if i % 10 == 9:
print(i)
This also works in Lua. However Lua includes the last number in the loop, unlike python.
-- lua code to do this
for i=1000, 9998 do
if i % 10 == 9 then
print(i)
end
end
However in both languages you could iterate by 10 each time
for i in range(1009, 9999, 10):
print(i)
for i=9, 9998, 10 do
print(i)
for var = 1000, 9000 do
if string.sub(var, -1) == "9" then
-- do your stuff
end
end
XY-Problem
The X problem of how to best port your code to Lua has been answered by quantumpro already, who optimized it & cleaned it up.
I'll focus on your Y problem:
What's the Lua equivalent of Python endswith?
Calling string functions, OOP-style
In Lua, strings have a metatable that indexes the global string library table. String functions are called using str:func(...) in Lua rather than str.func(...) to pass the string str as first "self" argument (see "Difference between . and : in Lua").
Furthermore, if the argument to the call is a single string, you can omit the parentheses, turning str:func("...") into str:func"...".
Constant suffix: Pattern Matching
Lua provides a more powerful pattern matching function that can be used to check whether a string ends with a suffix: string.match. str.endswith("9") in Python is equivalent to str:match"9$" in Lua: $ anchors the pattern at the end of the string and 9 matches the literal character 9.
Be careful though: This approach doesn't work with arbitrary, possibly variable suffices since certain characters - such as $ - are magic characters in Lua patterns and thus have a special meaning. Consider str.endswith("."); this is not equivalent to string:match".$" in Lua, since . matches any character.
I'd say that this is the lua-esque way of checking whether a string ends with a constant suffix. Note that it does not return a boolean, but rather a match (the suffix, a truthy value) if successful or nil (a falsey value) if unsuccessful; it can thus safely be used in ifs. To convert the result into a boolean, you could use not not string:match"9$".
Variable suffix: Rolling your own
Lua's standard library is very minimalistic; as such, you often need to roll your own functions even for basic things. There are two possible implementations for endswith, one using pattern matching and another one using substrings; the latter approach is preferable because it's shorter, possibly faster (Lua uses a naive pattern matching engine) and doesn't have to take care of pattern escaping:
function string:endswith(suffix)
return self:sub(-#suffix) == suffix
end
Explanation: self:sub(-#suffix) returns the last suffix length characters of self, the first argument. This is compared against the suffix.
You can then call this function using the colon (:) syntax:
str = "prefixsuffix"
assert(str:endswith"suffix")
assert(not str:endswith"prefix")
I'm trying to execute Sox from a Lua script.
It works fine when I pass literals as arguments.
os.execute('"C:\\Sox\\sox.exe" -S C:\\SoX\\test.wav -r 22050 C:\\Sox\\SoX_out.wav')
or
os.execute [["C:\\Sox\\sox.exe" -S C:\\SoX\\test.wav -r 22050 C:\\Sox\\SoX_out.wav]]
however, what I'd like to do (as example), when I try this:
filename = "C:\\SoX\\test.wav"
os.execute('"C:\\Sox\\sox.exe" -S filename -r 22050 C:\\Sox\\SoX_out.wav')
I get:
C:\Sox\sox.exe FAIL formats: can't open input file `filename': No such file or directory
So my question is how to pass a string properly as command argument ?
In Lua, a string literal is exactly and only that string. Strings don't know anything about variables, the global environment, local variables, etc. They're just strings. The string "filename" in Lua will always be a string of 8 characters. It will not go out and try to find a variable named filename and extract something from it.
What you want is to build a string, from multiple strings. Part of the string will come from literals, and part will come from a variable. Lua has several tools for that. The simplest is the .. concatenation operator:
[["C:\Sox\sox.exe" -S ]] .. filename .. [[ -r 22050 C:\Sox\SoX_out.wav]]
This builds a new string from a string literal, the contents of the filename variable, and another string literal. The spaces you see at the end of the first literal and the beginning of the second are necessary, since Lua will not insert spaces between the two concatenated pieces.
For more complex cases, it's useful to just build a table of parameters and use table.concat to build a string out of them:
local params =
{
[[C:\Sox\sox.exe]],
"-S",
filename,
"-r 22050",
[[C:\Sox\SoX_out.wav]]
}
os.execute(table.concat(params, " "))
Note the lack of spaces in the string literals. This is because table.concat's second parameter is a string to be inserted between the entries in the array. So between each array element will be a space; we don't need to manually add them.
So I'm writing a Lua script and I tested it but I got an error that I don't know how to fix:
.\search.lua:10: malformed pattern (missing ']')
Below is my code. If you know what I did wrong, it would be very helpful if you could tell me.
weird = "--[[".."\n"
function readAll(file)
local c = io.open(file, "rb")
local j = c:read("*all")
c:close()
return(j)
end
function blockActive()
local fc = readAll("functions.lua")
if string.find(fc,weird) ~= nil then
require("blockDeactivated")
return("false")
else
return("true")
end
end
print(blockActive())
Edit: first comment had the answer. I changed
weird = "--[[".."\n" to weird = "%-%-%[%[".."\r" The \n to \r change was because it was actually supposed to be that way in the first place.
This errors because string.find uses Lua Patterns.
Most non-alpha-numeric characters, such as "[", ".", "-" etc. convey special meaning.
string.find(fc,weird), or better, fc:find(weird) is trying to parse these special characters, and erroring.
You can use these patterns to cancel out your other patterns, however.
weird = ("--[["):gsub("%W","%%%0") .. "\r?\n"
This is a little daunting, but it will hopefully make sense.
the ("--[[") is the orignal first part of your weird string, working as expected.
:gsub() is a function that replaces a pattern with another one. Once again, see Patterns.
"%W" is a pattern that matches every string that isn't a letter, a number, or an underscore.
%%%0 replaces everything that matches with itself (%0 is a string that represents everything in this match), following a %, which is escaped.
So this means that [[ will be turned into %[%[, which is how find, and similar patterns 'escape' special characters.
The reason \n is now \r?\n refers back to these patterns. This matches it if it ends with a \n, like it did before. However, if this is running on windows, a newline might look like \r\n. (You can read up on this HERE). A ? following a character, \r in this case, means it can optionally match it. So this matches both --[[\n and --[[\r\n, supporting both windows and linux.
Now, when you run your fc:find(weird), it's running fc:find("%-%-%[%[\r?\n"), which should be exactly what you want.
Hope this has helped!
Finished code if you're a bit lazy
weird = ("--[["):gsub("%W","%%%0") .. "\r?\n" // Escape "--[[", add a newline. Used in our find.
// readAll(file)
// Takes a string as input representing a filename, returns the entire contents as a string.
function readAll(file)
local c = io.open(file, "rb") // Open the file specified by the argument. Read-only, binary (Doesn't autoformat things like \r\n)
local j = c:read("*all") // Dump the contents of the file into a string.
c:close() // Close the file, free up memory.
return j // Return the contents of the string.
end
// blockActive()
// returns whether or not the weird string was matched in 'functions.lua', executes 'blockDeactivated.lua' if it wasn't.
function blockActive()
local fc = readAll("functions.lua") // Dump the contents of 'functions.lua' into a string.
if fc:find(weird) then // If it functions.lua has the block-er.
require("blockDeactivated") // Require (Thus, execute, consider loadfile instead) 'blockDeactived.lua'
return false // Return false.
else
return true // Return true.
end
end
print(blockActive()) // Test? the blockActve code.
In Erlang, \" is an escape character that means double quote.
My question is, what is the difference between "\"test\"" and ""test""? The reason I ask is because, I'm trying to handle a list_to_atom error:
> list_to_atom("\"test\"").
'"test"'
> list_to_atom(""test"").
* 1: syntax error before: test
"" is a string/list of length 0
\" is just an escaped double-quote when used in the context of a string. If you wanted to have a string that consists of just a double-quote (ie \"), then you could do: "\"".
""test"" is a syntax error and is no difference than "" test "" which is syntactically <list><atom><list>. What are you trying to accomplish?
It's not advised to dynamically generate atoms as they're never garbage collected.
You'd better use list_to_existing_atom/1 when reading user input. Otherwise, you might end up running out of memory (in a system running long enough; but hey, that's what systems Erlang is for, isn't it?) and crashing the whole virtual machine.
list_to_existing_atom/1 will throw an error in case the atom doesn't exist and return the atom if it exists. A construct like catch list_to_existing_atom(some_atom) might prove useful coupled with a case .. of or a try ... catch block. Try it in the shell and see what you like the best.
If this answer seems irrelevant to the question, then please note I'm not allowed to post comments yet, so this answers the question in the comment to chops' answer, namely:
I have to write a function that reads from keyboard until an atom is typed.
I have to do this with get_line and list_to_atom. – otisonoza
I read a file:
local logfile = io.open("log.txt", "r")
data = logfile:read("*a")
print(data)
output:
...
"(\.)\n(\w)", r"\1 \2"
"\n[^\t]", "", x, re.S
...
Yes, logfile looks awful as it's full of various commands
How can I call gsub and remove i.e. "(\.)\n(\w)", r"\1 \2" line from data variable?
Below snippet, does not work:
s='"(\.)\n(\w)", r"\1 \2"'
data=data:gsub(s, '')
I guess some escaping needs to be done. Any easy solution?
Update:
local data = [["(\.)\n(\w)", r"\1 \2"
"\n[^\t]", "", x, re.S]]
local s = [["(\.)\n(\w)", r"\1 \2"]]
local function esc(x)
return (x:gsub('%%', '%%%%')
:gsub('^%^', '%%^')
:gsub('%$$', '%%$')
:gsub('%(', '%%(')
:gsub('%)', '%%)')
:gsub('%.', '%%.')
:gsub('%[', '%%[')
:gsub('%]', '%%]')
:gsub('%*', '%%*')
:gsub('%+', '%%+')
:gsub('%-', '%%-')
:gsub('%?', '%%?'))
end
print(data:gsub(esc(s), ''))
This seems to works fine, only that I need to escape, escape character %, as it wont work if % is in matched string. I tried :gsub('%%', '%%%%') or :gsub('\%', '\%\%') but it doesn't work.
Update 2:
OK, % can be escaped this way if set first in above "table" which I just corrected
:terrible experience:
Update 3:
Escaping of ^ and $
As stated in Lua manual (5.1, 5.2, 5.3)
A caret ^ at the beginning of a pattern anchors the match at the beginning of the subject string. A $ at the end of a pattern anchors the match at the end of the subject string. At other positions, ^ and $ have no special meaning and represent themselves.
So a better idea would be to escape ^ and $ only when they are found (respectively) and the beginning or the end of the string.
Lua 5.1 - 5.2+ incompatibilities
string.gsub now raises an error if the replacement string contains a % followed by a character other than the permitted % or digit.
There is no need to double every % in the replacement string. See lua-users.
According to Programming in Lua:
The character `%´ works as an escape for those magic characters. So, '%.' matches a dot; '%%' matches the character `%´ itself. You can use the escape `%´ not only for the magic characters, but also for all other non-alphanumeric characters. When in doubt, play safe and put an escape.
Doesn't this mean that you can simply put % in front of every non alphanumeric character and be fine. This would also be future proof (in the case that new special characters are introduced). Like this:
function escape_pattern(text)
return text:gsub("([^%w])", "%%%1")
end
It worked for me on Lua 5.3.2 (only rudimentary testing was performed). Not sure if it will work with older versions.
Why not:
local quotepattern = '(['..("%^$().[]*+-?"):gsub("(.)", "%%%1")..'])'
string.quote = function(str)
return str:gsub(quotepattern, "%%%1")
end
to escape and then gsub it away?
try
line = '"(\.)\n(\w)", r"\1 \2"'
rx = '\"%(%\.%)%\n%(%\w%)\", r\"%\1 %\2\"'
print(string.gsub(line, rx, ""))
escape special characters with %, and quotes with \
Try s=[["(\.)\n(\w)", r"\1 \2"]].
Use stringx.replace() from Penlight Lua Libraries instead.
Reference: https://stevedonovan.github.io/Penlight/api/libraries/pl.stringx.html#replace
Implementation (v1.12.0): https://github.com/lunarmodules/Penlight/blob/1.12.0/lua/pl/stringx.lua#L288
Based on their implementation:
function escape(s)
return (s:gsub('[%-%.%+%[%]%(%)%$%^%%%?%*]','%%%1'))
end
function replace(s,old,new,n)
return (gsub(s,escape(old),new:gsub('%%','%%%%'),n))
end