Lua is one of my favourite languages. It’s tiny, it’s fast, it has simplegrammar and is very easy to learn.
- C++ Run Lua Scripts
- C++ Execute Lua File
- Lua C++ Class
- C++ Execute Lua Script
- C++ Run Lua Script Download
Each Lua script requires only one priming run in order to create its globals so its functions are visible to the C program. In order to fully pass an integer into callfuncscript.lua's square function and receive the function's return, the luapcall's nargs argument must be 1 (one argument passed in) and its nreturns argument must be 1 (1. The first step is to define the function. All C or C functions that will be called from Lua will be called using a pointer of this type: typedef int (.luaCFunction) (luaState.L); In other words, functions must have a Lua interpreter as the only argument and return only an integer. Since a Lua interpreter is used for the argument, the.
I also often write shell scripts - from simple one-liners, to bigger onescontaining business logic and binding together smaller app components. In fact,this blog is powered by a few shell scripts to generate list of posts, rss xmletc.
I had an experience in the past when Bash script became hard to maintain. Thenwe moved to Lua, and it was a big relief. Logic became transparent, code becamemore readable. However, we had to wrap shell command invocations intohand-written functions to make them look nice.
So I made a library that brings the joy of shell scripting into Lua.
luash
Inspired by Python’s sh module, I took the same idea.
Every shell command can be invoked as a Lua function. For example, calling
echo hello world
in Lua would be echo('Hello', 'world')
.To achieve this I added a handler function for the missing table items in theglobals table. So if the script called a non-existent command (which is likelyto be a shell command wrapper) - my handler function started looking for therequested shell command and returned an appropriate wrapper function.
Then I had to implement the function
command(cmd)
to return a function, whichbeing invoked would run the actual command with all the arguments.At this point, we shall think about the commands chains (pipelines). Lua bynature is single-threaded and has blocking I/O. Which means you can either reador write at a time, and you can not do both simultaneously.
So to implement a pipeline the output of the previous command should bebuffered somewhere, and input should be sent using
io.write
function. Or theinput should be pre-written into some file, and sent to the command using shell‘<’ redirection, then the output could be read using io.read('*a')
function.Both ways seem to be equally good and help to avoid deadlocks.Here’s much more details about potential pitfalls with popen read/write.
Finally, the return value of the
command()
function should be a table, andthis table should be accepted by the outer command()
function (the next onein a pipeline). I decided to pass only command output, exit code and signalinside this “command result” table.And that’s all we have underneath the Lua sh module. You can see the fullimplementation of this module to learn more. It’s really tiny, less than 100lines of sparse code.
usage
First, require the Lua sh module:
At this point global table hook is already set up, you can start running yourshell commands:
Here’s how chaining looks like:
Also, since command output is buffered, you can store it and reuse as manytimes as needed. I personally find Lua syntax even more readable in this case:
You can provide stdin to the commands as a string passing a table with
__input
key:C++ Run Lua Scripts
Finally, commands that don’t fit the Lua syntax (like
google-chrome
or somecommand.bin
). Since we already have a function command(cmd)
that returns a command wrapper - we can use it, since it’s exported by the module:As a bonus, you can pre-define some command line arguments as well:
This is helpful for multi-command binaries, like
git
, docker
, ip
orbusybox
.Another syntax sugar is named options. You may pass a table instead of variadic arguments, then table keys will be interpreted as option names. Single-letter keys will be used as short options (
o
becomes -o
), longer keys will be used a long options (output
becomes --output
).summary
The library is super tiny, much more lightweight comparing to Python’s sh. Andof course it lacks lots of functionality that Python’s sh has:
- Stderr redirection (now stderr messages are printed to lua stderr). This canbe done via another file I think, but I don’t want to mess with shell a lot.I hope
<
operator works in most shells, while>&2 x > y
might not. - Subcommands as attributes (like
git.branch()
). I don’t think this featureis needed at all. One can define it easily with sh.command(). - Glob expansion. Again, I don’t see how this can be helpful, assuming that Luapasses commands via shell anyway, which does glob expansion already. E.g.
ls(/tmp/*')
already works. - No special API for “baking”, all is done via the same single
command()
APIfunction. - No “with” contexts (because Lua doesn’t have
with
keyword). - No iterative output. This might be interesting to implement, so one could do
for line in tail('-f', 'somefile') do .. done
- No callbacks to handle stdout/stderr. For most cases I think output can beprocesses after it’s fully read.
- No interactive callbacks (like expect for some output, send some input). Thisis because I/O is not suitable for interactive usage in Lua.
- No way to control buffer sizes (again, because we read full output at once).
- No way to set environment variable. Because Lua has no API for that.
- No way to attach tty. Because Lua has no API for that.
This means the library can still be improved. I haven’t tried it on Windows,but I think it should work with minor modifications. Special mode for loopsmight be added. Stderr redirection might be added after I ensure that it worksin all modern shells (bash, zsh, busybox, ash, mksh, windows cmd.exe etc).
But the library can already be used for most of the scripting needs. I hope it would help someone, and I’m glad to share it under MIT license.
Please, report any issues on github and pull requests are welcome!
I hope you’ve enjoyed this article. You can follow – and contribute to – on Github, Twitter or subscribe via rss.
Sep 03, 2015
Lua is one of my favourite languages. It’s tiny, it’s fast, it has simplegrammar and is very easy to learn.
I also often write shell scripts - from simple one-liners, to bigger onescontaining business logic and binding together smaller app components. In fact,this blog is powered by a few shell scripts to generate list of posts, rss xmletc.
C++ Execute Lua File
I had an experience in the past when Bash script became hard to maintain. Thenwe moved to Lua, and it was a big relief. Logic became transparent, code becamemore readable. However, we had to wrap shell command invocations intohand-written functions to make them look nice.
So I made a library that brings the joy of shell scripting into Lua.
Lua C++ Class
luash
Inspired by Python’s sh module, I took the same idea.
Every shell command can be invoked as a Lua function. For example, calling
echo hello world
in Lua would be echo('Hello', 'world')
.To achieve this I added a handler function for the missing table items in theglobals table. So if the script called a non-existent command (which is likelyto be a shell command wrapper) - my handler function started looking for therequested shell command and returned an appropriate wrapper function.
Then I had to implement the function
command(cmd)
to return a function, whichbeing invoked would run the actual command with all the arguments.At this point, we shall think about the commands chains (pipelines). Lua bynature is single-threaded and has blocking I/O. Which means you can either reador write at a time, and you can not do both simultaneously.
![Lua Lua](https://gta5mod.net/wp-content/uploads/2020/12/OTRCallouts-1.03.jpg)
So to implement a pipeline the output of the previous command should bebuffered somewhere, and input should be sent using
io.write
function. Or theinput should be pre-written into some file, and sent to the command using shell‘<’ redirection, then the output could be read using io.read('*a')
function.Both ways seem to be equally good and help to avoid deadlocks.Here’s much more details about potential pitfalls with popen read/write.
Finally, the return value of the
command()
function should be a table, andthis table should be accepted by the outer command()
function (the next onein a pipeline). I decided to pass only command output, exit code and signalinside this “command result” table.And that’s all we have underneath the Lua sh module. You can see the fullimplementation of this module to learn more. It’s really tiny, less than 100lines of sparse code.
usage
First, require the Lua sh module:
At this point global table hook is already set up, you can start running yourshell commands:
Here’s how chaining looks like:
Also, since command output is buffered, you can store it and reuse as manytimes as needed. I personally find Lua syntax even more readable in this case:
You can provide stdin to the commands as a string passing a table with
__input
key:Finally, commands that don’t fit the Lua syntax (like
google-chrome
or somecommand.bin
). Since we already have a function command(cmd)
that returns a command wrapper - we can use it, since it’s exported by the module:As a bonus, you can pre-define some command line arguments as well:
This is helpful for multi-command binaries, like
git
, docker
, ip
orbusybox
.Another syntax sugar is named options. You may pass a table instead of variadic arguments, then table keys will be interpreted as option names. Single-letter keys will be used as short options (
o
becomes -o
), longer keys will be used a long options (output
becomes --output
).summary
The library is super tiny, much more lightweight comparing to Python’s sh. Andof course it lacks lots of functionality that Python’s sh has:
- Stderr redirection (now stderr messages are printed to lua stderr). This canbe done via another file I think, but I don’t want to mess with shell a lot.I hope
<
operator works in most shells, while>&2 x > y
might not. - Subcommands as attributes (like
git.branch()
). I don’t think this featureis needed at all. One can define it easily with sh.command(). - Glob expansion. Again, I don’t see how this can be helpful, assuming that Luapasses commands via shell anyway, which does glob expansion already. E.g.
ls(/tmp/*')
already works. - No special API for “baking”, all is done via the same single
command()
APIfunction. - No “with” contexts (because Lua doesn’t have
with
keyword). - No iterative output. This might be interesting to implement, so one could do
for line in tail('-f', 'somefile') do .. done
- No callbacks to handle stdout/stderr. For most cases I think output can beprocesses after it’s fully read.
- No interactive callbacks (like expect for some output, send some input). Thisis because I/O is not suitable for interactive usage in Lua.
- No way to control buffer sizes (again, because we read full output at once).
- No way to set environment variable. Because Lua has no API for that.
- No way to attach tty. Because Lua has no API for that.
This means the library can still be improved. I haven’t tried it on Windows,but I think it should work with minor modifications. Special mode for loopsmight be added. Stderr redirection might be added after I ensure that it worksin all modern shells (bash, zsh, busybox, ash, mksh, windows cmd.exe etc).
But the library can already be used for most of the scripting needs. I hope it would help someone, and I’m glad to share it under MIT license.
Please, report any issues on github and pull requests are welcome!
C++ Execute Lua Script
I hope you’ve enjoyed this article. You can follow – and contribute to – on Github, Twitter or subscribe via rss.
C++ Run Lua Script Download
Sep 03, 2015