dax
Cross-platform shell tools for Deno and Node.js inspired by zx.
README
dax
Cross-platform shell tools for Deno and Node.js inspired by zx.
Differences with zx
1. Cross-platform shell.
- Makes more code work on Windows.
- Allows exporting the shell's environment to the current process.
- Uses deno_task_shell's parser.
- Has common commands built-in for better Windows support.
1. Minimal globals or global configuration.
- Only a default instance of $, but it's not mandatory to use this.
1. No custom CLI.
1. Good for application code in addition to use as a shell script replacement.
1. Named after my cat.
Executing commands
- ```ts
- #!/usr/bin/env -S deno run --allow-all
- import $ from "https://deno.land/x/dax/mod.ts";
- // run a command
- await $`echo 5`; // outputs: 5
- // outputting to stdout and running a sub process
- await $`echo 1 && deno run main.ts`;
- // parallel
- await Promise.all([
- $`sleep 1 ; echo 1`,
- $`sleep 2 ; echo 2`,
- $`sleep 3 ; echo 3`,
- ]);
- ```
Note: Above instructions are for Deno. For Node.js, install via npm install --save-dev dax-sh then import via import $ from "dax-sh";.
Getting output
Get the stdout of a command (makes stdout "quiet"):
- ```ts
- const result = await $`echo 1`.text();
- console.log(result); // 1
- ```
Get the result of stdout as json (makes stdout "quiet"):
- ```ts
- const result = await $`echo '{ "prop": 5 }'`.json();
- console.log(result.prop); // 5
- ```
Get the result of stdout as bytes (makes stdout "quiet"):
- ```ts
- const bytes = await $`gzip < file.txt`.bytes();
- console.log(bytes);
- ```
Get the result of stdout as a list of lines (makes stdout "quiet"):
- ```ts
- const result = await $`echo 1 && echo 2`.lines();
- console.log(result); // ["1", "2"]
- ```
Working with a lower level result that provides more details:
- ```ts
- const result = await $`deno eval 'console.log(1); console.error(2);'`
- .stdout("piped")
- .stderr("piped");
- console.log(result.code); // 0
- console.log(result.stdoutBytes); // Uint8Array(2) [ 49, 10 ]
- console.log(result.stdout); // 1\n
- console.log(result.stderr); // 2\n
- const output = await $`echo '{ "test": 5 }'`.stdout("piped");
- console.log(output.stdoutJson);
- ```
Getting the combined output:
- ```ts
- const result = await $`deno eval 'console.log(1); console.error(2); console.log(3);'`
- .captureCombined();
- console.log(result.combined); // 1\n2\n3\n
- ```
Piping
Piping stdout or stderr to a Deno.WriterSync:
- ```ts
- await $`echo 1`.stdout(Deno.stderr);
- await $`deno eval 'console.error(2);`.stderr(Deno.stdout);
- ```
Piping to a WritableStream:
- ```ts
- await $`echo 1`.stdout(Deno.stderr.writable, { preventClose: true });
- // or with a redirect
- await $`echo 1 > ${someWritableStream}`;
- ```
To a file path:
- ```ts
- await $`echo 1`.stdout($.path("data.txt"));
- // or
- await $`echo 1 > data.txt`;
- // or
- await $`echo 1 > ${$.path("data.txt")}`;
- ```
To a file:
- ```ts
- using file = $.path("data.txt").openSync({ write: true, create: true });
- await $`echo 1`.stdout(file);
- // or
- await $`echo 1 > ${file}`;
- ```
From one command to another:
- ```ts
- const output = await $`echo foo && echo bar`
- .pipe($`grep foo`)
- .text();
- // or using a pipe sequence
- const output = await $`(echo foo && echo bar) | grep foo`
- .text();
- ```
Providing arguments to a command
Use an expression in a template literal to provide a single argument to a command:
- ```ts
- const dirName = "some_dir";
- await $`mkdir ${dirName}`; // executes as: mkdir some_dir
- ```
Arguments are escaped so strings with spaces get escaped and remain as a single argument:
- ```ts
- const dirName = "Dir with spaces";
- await $`mkdir ${dirName}`; // executes as: mkdir 'Dir with spaces'
- ```
Alternatively, provide an array for multiple arguments:
- ```ts
- const dirNames = ["some_dir", "other dir"];
- await $`mkdir ${dirNames}`; // executes as: mkdir some_dir 'other dir'
- ```
If you do not want to escape arguments in a template literal, you can opt out completely, by using $.raw:
- ```ts
- const args = "arg1 arg2 arg3";
- await $.raw`echo ${args}`; // executes as: echo arg1 arg2 arg3
- ```
Providing stdout of one command to another is possible as follows:
- ```ts
- // Note: This will read trim the last newline of the other command's stdout
- const result = await $`echo 1`.stdout("piped"); // need to set stdout as piped for this to work
- const finalText = await $`echo ${result}`.text();
- console.log(finalText); // 1
- ```
...though it's probably more straightforward to just collect the output text of a command and provide that:
- ```ts
- const result = await $`echo 1`.text();
- const finalText = await $`echo ${result}`.text();
- console.log(finalText); // 1
- ```