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.
Related
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.
How do I replace a string between a set of delimiter strings with sed? The first delimiter is a string which is not replaced while; the second delimiter is a single char but needs to be replaced as part of the replacement.
i.e.
FIRST_DELEM="GetVal("
SECOND_DELEM=”,”
Example string:
abc = param.GetVal((m_AstringToReplace, xml_SomeData, StringParameter(L""));
The String to replace or remove = (m_AstringToReplace,
This following sed command will only parse out the string, it does not replace it.
sed -e 's/.*GetVal(\(.*\),.*/\1/'
How would I use sed to replace the string using these complex delimiters ?
With this as input:
$ cat file
abc = param.GetVal((m_AstringToReplace, xml_SomeData, StringParameter(L""));
This performs the replacement of the string that starts immediately following GetVal( and ends with the first comma:
$ sed -re 's/(GetVal[(])[^,]*,/\1REPLACEMENT/' file
abc = param.GetVal(REPLACEMENT xml_SomeData, StringParameter(L""));
The regex (GetVal[(]) captures the first delimiter into group 1. [^,]*, matches all that follows up to and including the first comma, ,.
Note that, if we had used .*, in place of [^,]*,, then we would have matched everything up to the last comma in the string.
In the replacement part of the substitution, \1 restores the first delimiter, the one we wanted to keep. All that follows is the replacement, whatever you want it to be.
I have a script that is a command line parser , it calls other scripts. One script that it calls is count.s. count.s takes 1 arg and counts words lines chars, it will accept a *.txt and works fine. In the command line parser argv[1] is *.c When I call it from my command line parser , and pass into count.s argv[1], it expands *.c and count.s only reads the first file it enounters. I think I need to take argv[1] , which is a *.whatever and take it as a literal.
How can I do this? I think I need to turn off the filename expansion in the command line parser and pass into count.s the actual *.whatever , instead of the expansion that occurs within the command line parser.
I can post my code if it helps , but I dont think it is really necessary
Basically, you can't.
The argument *.c is expanded by the shell before your script ever sees it.
Suppose the current directory contains foo.c and bar.c. If you type
myscript.csh *.c
then myscript.c will see bar.c and foo.c as two separate arguments -- exactly as if you had typed
myscript.csh bar.c foo.c
at the command line.
If you want your script to see the string *.c, then you have to pass that as an argument, which you can do by quoting the argument:
myscript.csh '*.c'
But your script has no control over how and whether wildcards are expanded.
What are you actually trying to accomplish?
I have two strings - each string has many lines like the following:
string1 = " DEFAULT-VLAN | Manual 10.1.1.3 255.255.255.0 "
string2 = " 1 DEFAULT-VLAN | Port-based No No"
The first string I split into the following strings: "DEFAULT-VLAN", "|", "Manual"...
Then I want to look up the ID ("1") in string2 for the vlanName ("DEFAULT-VLAN") from string1.
I use this code to find the correct substring:
vpos1, vpos2 = vlan:find("%d-%s-" .. vlanName .. "%s-|")
But vpos1 and vpos2 are nil; When the hyphen ("-") is deleted from the vlanName it is working.
Shouldn't Lua take care to escape the special characters in such strings? The string is handed over from my C++ application to Lua and there may be lots of special characters.
Is there an easy way to solve this?
Thanks!
Lua is not magic. All the expression "%d-%s-" .. vlanName .. "%s-|" does is concatenate some strings, producing a final string. It has no idea what that string is intended to be used for. Only string.find knows that, and it can't have any affect on how the parameter it is given will be used.
So yes, vlanName will be interpreted as a Lua pattern. And if you want to use special characters, you will need to escape them. I would suggest using string.gsub for that. It'd be something like this:
vlanName:gsub("[%-...]", "%%%0")
Where ... are any other characters you want to escape.
I'm trying to pass a byte array from inside my rails app into another ruby script (still inside my rails app), for example:
`./app/animations/fade.sh "\x01\x01\x04\x00" &`
Yields ArgumentError (string contains null byte)
I suppose I'm stumped with how I can form this string and than pass it to my script, which will use it in this sort of fashion:
#sp.write ["#{ARGV[0]}", "f", "\x12"]
I'd like to form the string (on my rails app) like this if possible:
led = "\x01#{led.id}\x04\x00"
But I keep getting ArgumentError (string contains null byte) error. Is there a way I can form this string from elements in my rails app, then pass it to my external script?
You should just pass the data in through standard input, not the command line. You can use IO.popen for this purpose:
IO.popen("./app/animations/fade.sh", "w+") do |f|
f.write "\x01\x01\x04\x00"
end
And on the reading side:
input = $stdin.read
#sp.write [input, "f", "\x12"]
(By the way, it's more common to name Ruby scripts .rb instead of .sh; if fade.sh is meant to be a Ruby script, as I assume from the syntax you used in its example contents, you might want to name it fade.rb)
you could use base64 to pass the bytestring around
$ cat > test.sh
echo $1 | base64 -d
$ chmod a+x test.sh
and then from ruby:
irb
>> require 'base64'
=> true
>> `./test.sh "#{Base64.encode64 "\x01\x01\x04\x00"}"`
=> "\x01\x01\x04\x00"
Can your script accept input from STDIN instead? Perhaps using read.
If you can't do this, you could encode your null and escape your encoding.
E.G. 48656c6c6f0020576f726c64 could be encoded as 48656c6c6f200102020576f726c64
which in turn would be decoded again if both sides agree 2020=20 and 2001=00
Update I think encoding is what you'll have to do because I tried using read and it turns out to be a little too difficult. There's probably another option, but I don't see it yet.
Here's my script and two test runs:
dlamblin$ cat test.sh
echo "reading two lines of input, first line is length of second."
read len
read ans
echo "C string length of second line is:" ${#ans}
for ((c=0; c<$len; c++))
do
/bin/echo -n "${ans:$c:1},"
done
echo ' '
exit
dlamblin$ echo -e '12\0012Hello \0040World' | sh test.sh
reading two lines of input, first line is length of second.
C string length of second line is: 12
H,e,l,l,o, , ,W,o,r,l,d,
dlamblin$ echo -e '12\0012Hello \0000World' | sh test.sh
reading two lines of input, first line is length of second.
C string length of second line is: 5
H,e,l,l,o,,,,,,,,
#Octals \0000 \0012 \0040 are NUL NL and SP respectively