The package is in early stage, some changes (in API) may be made until version 1.0.0.!
This package serves as an alternative to google/zx for example. The key difference is to provide Unix shell commands in a cross-platform compatible way and usable inside JavaScript. This is primarily achieved by using shelljs/shelljs library.
You can compare the final script code to zx
example:
#!/usr/bin/env nodejsscript
echo(s.grep("name", "package.json"));
s.run("git branch --show-current")
.xargs(s.run, "dep deploy --branch={}");
s.run("sleep 1; echo 1");
s.run("sleep 2; echo 2");
s.run("sleep 3; echo 3");
const name= "foo bar";
s.mkdir($.xdg.temp(name));
…also see examples. You can also use nodejsscript -e
/nodejsscript -p
in shell:
curl https://api.spacexdata.com/v4/launches/latest | nodejsscript -p 'Object.entries($.nojq).filter(([_,v])=> Array.isArray(v))'
…see examples again.
- migration from 0.8.*: see API changes 0.8 → 0.9
- potencial changes for 1.x.y: see issues
- tested/used on NodeJS:
node@v16.13.0
andnode@v17.9.1
⇒ for installation follow nvm-sh/nvm: Node Version Manager1 npm install nodejsscript --location=global
… alternatively install locally:npm install nodejsscript
2
s #shelljs · $ ($.api() #sade, $.read(), $.xdg, …) · echo() #css-in-console · fetch() #node-fetch · pipe() · cyclicLoop()
Write your scripts in a file with an .mjs
extension in order to
use await
at the top level. If you prefer the .js
extension,
wrap your scripts in something like (async function () {...})()
.
Add the following shebang to the beginning of your nodejsscript
scripts:
#!/usr/bin/env nodejsscript
Now you will be able to run your script like so:
chmod +x ./script.mjs
./script.mjs
Or via the nodejsscript
executable:
nodejsscript ./script.mjs
Alternatively when installed locally
#!/usr/bin/env -S npx nodejsscript
npx nodejsscript ./script.mjs
All function (shelljs
, fetch
, …) are registered as global namespaces/functions:
… The entry point for documentation of all Public items is in the docs/.
Note that there are also built-in 'node:*'
modules:
import { setTimeout } from "node:timers/promises";
import { join, resolve } from "node:path";
//.current file url
import.meta.url;
//.url to path
import { fileURLToPath } from "node:url";
const file_path= fileURLToPath(import.meta.url);
// url is supported! (see relative reading)
s.cat(new URL('relative_file', import.meta.url));
//.crypto utils
import { randomUUID } from "node:crypto";
// …
…and more, see Node.js v17.9.1 Documentation.
run()
/runA()
command injection: this advice applies to child_process.exec()
just as
much as it applies to s.run()
. It is potentially risky to run commands passed
for example by user input:
function curlUnsafe(urlToDownload){ return s.run('curl ' + urlToDownload); }
curlUnsafe('https://some/url ; rm -rf $HOME'); //=> curl https://some/url ; rm -rf $HOME
Therefore, nodejsscript
s s.run()
provide way to escapes untrusted parameters:
function curl(url){ return s.run("curl ::url::", { url }); }
curl('https://some/url ; rm -rf $HOME'); //=> curl 'https://some/url ; rm -rf $HOME'
…you can also use as template function (but without command specific options):
function curl(url){ return s.run`curl ${url}`; }
curl('https://some/url ; rm -rf $HOME'); //=> curl 'https://some/url ; rm -rf $HOME'
…Note: The 'xargs()' by default also escapes piped strings.
…Note 2: s.run(…cmd, …vars)
is also helpul for escaping parameters passed as variables (e.g. arrays).
…Note 3: ShellJS also provides s.exec
, but s.run
should be prefered way to execute commands.
Glob injection (all commands): Most ShellJS commands support glob expansion,
expanding wildcards such as *
to match files. While this is very powerful,
dependent modules should exercise caution. Unsanitized user input may contain
wildcard characters. Consider for example that the *.txt
is valid file name,
however the s.rm("*.txt")
by default (using the globbing) delete all txt
files.
Keep in mind that you can always turn off this for next command by using:
s.$("-g").rm("*.txt");
You can create jsconfig.json
to help your editor provide proper suggestions.
As editor you can use VSCode or Vim with for example neoclide/coc.nvim.
NodeJSScript provides nodejsscript --global-jsconfig add script_file
to
help generate jsconfig.json
.
The runA
is almost identical to $
:
await $`cat package.json | grep name`;
await s.runA`cat package.json | grep name`;
…but for cp
/mv
/… you need to rewrite code to s.*
:
echo(s.cat("package.json").grep("name"));
// or
echo(s.grep("name", "package.json"));
cli
renamed to$
style
(ansi-colors
) removed in favour of using “CSS” inecho
exit
removed in favour of$.exit