vl
Shell scripting with TypeScript. Runs on top of Deno.
vl
started as a port of zx
to deno. The main
motivation for this package was the lack of typescript support in zx
. That’s
where I got the idea to use deno
, since it supports TypeScript natively.
Bash is great, but when it comes to writing scripts, it has it’s limitations and
people tend to go for more expressive programming languages.
JavaScript/TypeScript is a great choice, since they are approachable by a huge
number of developers. The vl
package provides provides wrappers around
child_process
, and a number of other things for all your shell scripting
needs. Since vl
uses deno
, it has access to both the rich standard library
of deno, and the battle tested standard
libraries of node through it’s
node compatibility.
#!/usr/bin/env vl
import "https://deno.land/x/violet/globals.d.ts";
const { create, mkdir } = Deno;
await Promise.all([
$`sleep 1; echo 1`,
<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">‘</mi><mi>s</mi><mi>l</mi><mi>e</mi><mi>e</mi><mi>p</mi><mn>2</mn><mo separator="true">;</mo><mi>e</mi><mi>c</mi><mi>h</mi><mi>o</mi></mrow><annotation encoding="application/x-tex">`sleep 2; echo </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord">‘</span><span class="mord mathnormal">s</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">ee</span><span class="mord mathnormal">p</span><span class="mord">2</span><span class="mpunct">;</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord mathnormal">ec</span><span class="mord mathnormal">h</span><span class="mord mathnormal">o</span></span></span></span>{2}`,
$`sleep 3; echo 3`,
]);
await fetch("https://google.com");
await mkdir("tests");
await create("tests/test.txt");
cd("tests");
await $`ls`;
cd("..");
// clean up
await $`rm -rf tests`;
$command
Executes the given command by spawning a subprocess. Everything passed through
${}
will be automatically quoted.
const fileName = "awesome";
await <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">‘</mi><mi>t</mi><mi>o</mi><mi>u</mi><mi>c</mi><mi>h</mi></mrow><annotation encoding="application/x-tex">`touch </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord">‘</span><span class="mord mathnormal">t</span><span class="mord mathnormal">o</span><span class="mord mathnormal">u</span><span class="mord mathnormal">c</span><span class="mord mathnormal">h</span></span></span></span>{awesome}.txt`;
You can also pass an array of arguments.
const flags = ["--oneline", "--decorate", "--color"];
const { exitCode } = await <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">‘</mi><mi>g</mi><mi>i</mi><mi>t</mi><mi>l</mi><mi>o</mi><mi>g</mi></mrow><annotation encoding="application/x-tex">`git log </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord">‘</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mord mathnormal">i</span><span class="mord mathnormal" style="margin-right:0.01968em;">tl</span><span class="mord mathnormal">o</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span></span></span></span>{flags}`;
Pipelines
#!/usr/bin/env vl
import "https://deno.land/x/violet/globals.d.ts";
await $`echo "Hello, stdout!"`
.pipe(fs.createWriteStream("/tmp/output.txt", {}));
await $`cat /tmp/output.txt`;
Environment variables
#!/usr/bin/env vl
import "https://deno.land/x/violet/globals.d.ts";
Deno.env.set("FOO", "bar");
await <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">‘</mi><mi>e</mi><mi>c</mi><mi>h</mi><mi>o</mi></mrow><annotation encoding="application/x-tex">`echo </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord">‘</span><span class="mord mathnormal">ec</span><span class="mord mathnormal">h</span><span class="mord mathnormal">o</span></span></span></span>FOO > tmp.txt`;
await $`cat tmp.txt`;
Functions
fetch
works, since it’s natively supported in deno.
const resp = await fetch("https://wttr.in");
console.log(await resp.text());
ask
reads a line from stdin.
const resp = await ask("What is your name?");
console.log(resp);
sleep
sleeps for specified ms.
await sleep(2000);
noThrow()
Changes the behaviour of $
to not throw an exception on non-zero
exit codes. You can still access the exitCode
from the response.
const { exitCode } = await noThrow($`exit 1`);
console.log(exitCode);
quiet()
Changes the behaviour of $
to disable verbose output.
usage:
await quiet($`echo foobar`); // command and output will not be displayed.
os
package.
usage:
await <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">‘</mi><mi>e</mi><mi>c</mi><mi>h</mi><mi>o</mi></mrow><annotation encoding="application/x-tex">`echo </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6944em;"></span><span class="mord">‘</span><span class="mord mathnormal">ec</span><span class="mord mathnormal">h</span><span class="mord mathnormal">o</span></span></span></span>{os.homedir()}`;
retry()
Retries a command as many times as specified. Returns the first successful attempt, or will throw after specified attempts count.
usage:
await retry(5)`curl localhost`;
// or with a specified delay (500ms)
await retry(5, 500)`curl localhost`;
startSpinner()
Displays a spinner as an loading indicator. Useful with long running processes.
usage:
const { stopSpinner } = startSpinner();
await sleep(5000);
stopSpinner();
Configuration
$.shell
Which shell is used. Default is bash.
$.shell = "/usr/bin/zsh";
CLI argument --shell=/usr/bin/zsh
can be used to achieve the same result.
$.verbose
can be used to specify verbosity.
Default is true
.
CLI argument --quiet
sets verbosity to false
.
Prerequisites
You need to have deno
installed. You can find installation instructions at
deno.land.
Install
deno install --allow-all -f https://deno.land/x/violet@<version_number>/vl.ts