Tiny library for shell scripting with Lua (inspired by Python's sh module).
This fork of luash removes the pollution of _G, for safer use in unknown environments.
It also improves keyed-table argument parsing, adding support for function references, replacing underscores with dashes in keys, and so forth. Please read below.
Even if you read the README in zserge/luash, please read this in its entirety as well.
Clone this repo and copy sh.lua into your project, or install with luarocks --local make rockspec/luash-scm-0.rockspec.
localsh=require("sh")
-- Get command references (not yet executed)localls=sh("ls") -- vararg, can do: local ls, wc = sh("ls", "wc")localls=sh/"ls" -- shorthand, same thinglocalls=sh.command("ls") -- explicit, slightly more efficient-- Execute and get chainable result tablelocalref=ls("/bin") -- call the command referencelocalref=sh._"ls /bin" -- shorthand for sh("ls")("/bin")-- Get stdout as stringlocalout=tostring(ref) -- trimmed stdout from resultlocalout=sh%"ls /bin" -- execute and return trimmed stdout directly-- Chaining (nested or piped syntax)wc(grep(ls("/bin"), "ash"), "-l")
ls("/bin"):grep("ash"):wc("-l")
ls"/bin" : grep"ash" : wc"-l" -- Lua allows omitting parens-- Fire-and-forgetsh._"curl -O http://example.com/file"That's it. Everything below is just details.
localsh=require("sh")
localwc, grep=sh("wc", "grep")
localls=sh.command("ls")
localref=wc(grep(ls("/bin"), "ash"), "-l")
print(type(ref)) -- tableprint(tostring(ref)) -- "8" (or whatever the count is)print(ref.__exitcode) -- 0print(ref.__cmd) -- the actual command that was runSame as sh.command("cmd"). Returns an unexecuted command reference.
localwc, grep, ls=sh/"wc", sh/"grep", sh/"ls"Executes immediately and returns trimmed stdout as a string.
localstdout=sh%"ls /bin | grep ash | wc -l"print(type(stdout)) -- stringExecutes immediately and returns the result table. Useful for fire-and-forget or when you need the result but want concise syntax.
sh._"git push"sh._"curl --silent -O http://example.com/file"-- These are equivalent:localret=sh("ls")("/bin")
localret=sh._"ls /bin"Note: sh%"git push" and sh/"git push" are syntax errors in Lua. Use sh._ when you need a one-liner that executes.
localsh=require("sh")
-- Command reference (not yet executed)localcmd=sh("whoami")
print(type(cmd)) -- table-- Executed result (has __input, __exitcode, etc)localresult=cmd()
print(type(result)) -- tableprint(result.__input) -- raw stdoutprint(tostring(result)) -- trimmed stdoutprint(result.__exitcode) -- 0 on successprint(result.__signal) -- signal if killedprint(result.__cmd) -- actual command string-- Direct string outputlocalstr=sh%"whoami"print(type(str)) -- stringKey-value arguments can be passed as a table. Keys become flags, values become their arguments.
localfoo=sh("foo")
foo({
format="long", -- --format='long'interactive=true, -- --interactiveu=3, -- -u=3 (single-char keys get one dash)replace_underscore="x", -- --replace-underscore='x'removed=false, -- (omitted entirely)
})If #table > 0 (i.e., it has array elements), key-value pairs are ignored and only indexed values are used.
Functions can be used as keys or values - they're called with the inverse as an argument, and returning nil omits that flag.
Commands can be nested or chained. The inner command runs first, its output is passed via temp file to the outer command.
localuniq, sort=sh("uniq", "sort")
localwords="foo\nbar\nfoo\nbaz\n"localu=uniq(sort({__input=words}))
print(u) -- bar, baz, foo-- Chained syntax (allocates new metatables per chain)ls("/bin"):grep("ash"):wc("-l")
-- Or without parensls"/bin" : grep"ash" : wc"-l"Note: Chaining allocates a new function metatable per command and doesn't use your local upvalues from sh(...).
Each result table has __exitcode and __signal fields. Zero exit status means success.
Since f:close() returns exitcode and signal in Lua 5.2+, this won't work in Lua 5.1 or current LuaJIT.
__cmd holds the actual command line that was executed. It doesn't concatenate through chains, so ls("/bin"):grep("ash"):wc("-l").__cmd only shows the final wc command.
Code is distributed under the MIT license.