Skip to content

LuaSH

Shell scripting in Lua: every program on PATH is a function, its output is a value, and chains read like shell pipelines.

local sh = require("sh")

print(sh.ls("-l"))                        -- run a program, print its output
print(sh.seq(1, 10):grep("5"):wc("-l"))   -- 1: stdout feeds the next stdin
print("I am " .. sh.whoami())             -- Results concatenate
sh.install()                              -- undefined globals become commands
print(wc(seq(1, 100), "-l"))              -- 100

LuaSH runs on Lua 5.1 to 5.5 and LuaJIT and needs no C module. Programs start through luaposix or luv when one of them is installed, and through Lua's own io.popen otherwise. Each command returns a Result with stdout, stderr, the exit status, the signal and the pipeline that produced it; a failing command raises, unless you ask it not to.

Install

Any of these gives require("sh"):

luarocks install sh
curl -LO https://github.com/JBlaschke/luash/releases/latest/download/sh.lua

The second is the whole library in one file, attached to every release; replace latest with download/v2.0.0 for a pinned version, and put the file anywhere on package.path. In a clone, standalone/sh.lua is the same file.

Important

luaposix and luv are optional. They are weak dependencies, in the sense that they are resolved, if present, when the library is loaded or a backend is changed. Either one gives a faster and more secure backend that streams stderr separately and reports signals:

luarocks install luaposix   # or: luarocks install luv

Without them, commands run through io.popen and a shell, and the popen backend's file strategies keep stdin and stderr in temp files (pipes in each backend).

Where to look

Backends at a glance

Backend Needs stdin stderr Signals
posix luaposix yes separate yes
luv luv yes separate yes
popen io.popen only depends on the strategy depends on the strategy no

The first available one in the platform's order is used; sh.backend_name() tells which, and sh.set_backend("popen", { strategy = "standard" }) switches. Backend resolution has the details.