Wrapper around `shelljs` to use it in CLI mode.
npm install jsshnpm package.
./portable/jssh.js. This file is a single .js bundle with everything jssh needs to run.
jssh on Node OS. This is just for testing purposes,
jssh with Node OS.
jssh:
readline module, so you might want to opt for a colorless prompt:
jssh in your console.
jssh exposes a number of global functions to work with your machine. In particular,
jssh-api-jssh, which internally uses
shelljs package for Unix-like shell commands.
ls returns the same results as ls(), that is because jssh executes automatically a functions if that is part
> symbol. This way your commands will be 'proxied' to the native system shell
entrypoint property in the configuration file.
#! or //> (instead of >) to execute shell commands. Advantage of using //> is that
// starts a comment, which makes your command a valid JavaScript code. (Use #! for CoffeScript. Yes, you can
$ symbol like so: $>, //$>, #$>, or #!$.
$ provided by the jssh-api-jssh API (see below on APIs).
help command pretty-prints help information stored with the commands available through .help() method. Get the raw
ln.help().
jssh uses // syntax at the end of line to indicate that the code will continue on the next line. *This is an experimental
\
jssh.exportHistory() method.
cd function, for example, to move one folder up, do cd('..').
cd .., fortunately
jssh allows you to use any language that compiles to JavaScript, for example, CoffeeScript has a much easier syntax.
lang property in config to specify the language you want to use, here is how to start a CoffeeScript shell:
jssh session from the current one with > jssh.
slap package with > npm install -g slap, then do:
slap, press Ctrl + S, ENTER to save, then Ctrl +
slap. Run your script:
jssh should execute '.js' files. I.e. :
1234:
--config-file and --config overwrite the default config, see Configuration.
--code executes code, like jssh --code 'console.log(123)'.
--port, -p tells jssh to listen to a port or a UNIX socket instead of STDIN for commands. When running with
--stdio, -s tells jssh to start in a headless mode, i.e. it will not have a prompt and will
jssh reads this default config file, which you can override in two ways.
--config-file CLI option you can tell jssh to read your .json config file, which will override the defaults.
--config to pass serialized JSON object right from the console, like so:
chalk:
javascript
var chalk = require('chalk');
var prompt = chalk.green(' >>> ');
console.log(JSON.stringify(prompt)); // "\u001b32m >>> \u001b[39m"
`
List of variables:
- {{HOSTNAME}}
- {{HOSTNAME_SHORT}}
- {{USER}}
- {{LANG}}
- {{LANG_SHORT}}
- {{CNT}}
- {{TIME}}
- {{HOURS}}
- {{MINUTES}}
- {{SECONDS}}
- {{CWD}}
- {{CWD_SHORT}}
- {{BUFFERED_LINES}}
- {{BUFFERED_LINES_+1}}
$3
Specifies a path to a PEG.js grammar file, see [Grammar for details.
- grammar -- When you type your command and press ENTER in the shell, jssh uses this grammar to
figure out which action to execute, see Grammar below.
$3
An array of command and arguments to use to proxy shell commands like > ifconfig.
The default is ['/bin/sh', '-c']. If set to null, jssh will try to execute your commands with Node's
child_process.spawn method directly.
$3
Snippets
jssh 'snippets' are basically JavaScript files that get executed in the context created by jssh shell, thus, they can
take full advantage of commands provided by jssh. Run your file like this:
jssh snippet.js
You can use this for automating build tasks or provisioning servers (this was actually the reason for
creating jssh in the first place). The author of jssh uses Docker to provision servers, however, you cannot
put advanced logic such as if-else statements of for loops into the Dockerfile. This makes you use other tools like
Puppet or Chef, or going back to good old BASH scripts. How sad is it that there is no framework written in Node.js
to provision servers? Since the author already uses JavaScript for everything (i.e. backend, frontend, mobile apps,
build tools etc.) and has Node.js installed on every machine, it seemed nice to be able to write simple "BASH" scripts
in JavaScript as well. Thats-why jssh was created, to execute JS line-by-line in a command line interface, to see
the results interactively, then just put those same commands in a .js file (what shelljs does), and voal�.
Here is how you install an Nginx server on Ubuntu, in CoffeeScript:
`coffeescript
nginx.coffee
Check if Nginx is not already installed.
if not which 'nginx'
# Install default Nginx server using APT.
$ 'apt-get update'
$ 'apt-get install -y nginx'
# Clean-up after APT.
$ 'apt-get clean'
rm '-rf', ['/var/lib/apt/lists/', '/tmp/', '/var/tmp/*']
$ 'service nginx start'
echo GET '127.0.0.1'
`
Your IDE probably already automatically compiles .coffee files to .js (if not, I recommend
Webstorm), then you just do:
jssh nginx.js
If you still want to run the .coffee file itself, do:
jssh --config '{"lang": "coffee"}' nginx.coffee
API
API of jssh are global functions that get exposed to the running context. APIs are basically npm packages whose
methods get exposed as global functions, for example, that is how you can run different 'commands' in the console, like
ls() or cd(), etc.
Run jssh with functions provided by shelljs package:
jssh --config '{"api":[[null, "shelljs"]]}'
Use jssh-api-jssh-bin instead provides id, chown commands.
jssh --config '{"api":[[null, "jssh-api-jssh-bin"]]}'
Grammar
jssh does not have a predefined command language, but rather it just executes actions. The grammar tells jssh
which actions to execute.
Grammar in defined in PEG.js syntax; the default one is stored in
./grammar/default.peg file. You can provide your own one by overwriting the grammar property
in the config.
Currently, jssh knows how to execute these three actions: code, exec, exec_code.
- code -- This action evaluates the JavaScript code, like when you type ls(), jssh evaluates the global ls
function running in that context. If shell is running in different language, say CoffeeScript, it first compiles it
to JavaScript.
- exec -- This action proxies the command to the entrypoint defined in the config. If entrypoint is not defined,
it just uses child_process.spawn. This action runs when you type in console commands prefixed with >, like > ifconfig.
- exec_code -- This action is like exec, but first it evaluates the code like the code action, for example,
$> "p" + "w" + "d".
The actions that jssh receives from PEG.js are in the following format:
> npm install jssh --no-bin-links
{
action: "exec",
payload: {
command: "npm",
arguments: ["install", "jssh", "--no-bin-links"]
}
}
console.log('Hello world');
{
action: "code",
payload: {
code: "console.log('Hello world');"
}
}
P.S. It actually has another command reserved, stream, with a tilde syntax: ~ fs.createReadStream('file.txt'). It
is not implemented yet, but it will do something interesting with the streams. Suggestions are welcome!
P.P.S. There is actually another command . (a single dot). That is a shorthand for writing this:
$> process.argv.join(" ")
identical to:
.
Can you guess what it does?
$3
Default: --api=shelljs
A comma separated list of packages to use as global API for the the shell session. An "API" is considered a static object,
whose properties will be exported to the global namespace, this allows us to run those functions in the shell as commands.
For example, when you run ls command in the shell to display a list of files in the current directory, it is not
implemented by jssh itself, but rather it is imported from the shelljs package:
jssh > ls
[ 'bin',
...
]
You can add extra API simplify many tasks. For example, to simplify deployment tasks use mecano.
jssh --api=shelljs,mecano
...
Namespace APIs.
jssh --api=shelljs,dep:deply_package
You can create your own API.
// my-api.js
module.exports = {
time: function() {
return +new Date();
}
};
Add your custom API
$3
Sets a custom prompt string. Specify a string or JSON string as your prompt.
Usage:
jssh --prompt 'My Prompt > '
Default: jssh >
You can add colors to your prompt. To add color information, you have to provide string serialized in JSON, which
contains console color information.
Let's say we want a prompt that displays our username in
jssh
require
Create your own colorful prompt.
var chalk = require("chalk");
var prompt = chalk.green("jssh") + " @ " + chalk.yellow("{{CWD}} > ");
var str = JSON.stringify(prompt);
console.log(str); // "\u001b32mjssh\u001b[39m @ \u001b[33m{{CWD}} > \u001b[39m"
Use your colorful prompt:
jssh --prompt '"\u001b[32mjssh\u001b[39m @ \u001b[33m{{CWD}} > \u001b[39m"'
$3
TODO:
Export a global make variable, which is an empty object. Allow to run command from command line after the file is
executed, to run a specific make command.
#!/usr/bin/env jssh --lang coffee --make
make.all ->
make.compile()
make.deploy()
make.compile ->
# ...
make.deploy ->
# ...
Run the deploy command:
makefile all
jssh -f makefile --lang coffee --make all
$3
docker run -it --rm streamich/jssh jssh
Dockerfile:
...
TODOs
Portability: (1) edit Npm.ts; (2) async HTTP requests.
Create another JavaScript language, that would be well suited for executing shell commands. It could be a dialect of
CoffeScript. One feature could be to have strings without quotes, just like in YAML files. Then you could do:
jssh > ls ~
Instead of (in JavaScript and CoffeScript):
jssh > ls("~")
jssh > ls '~'
Could borrow some ideas from [nshell, like events
and sourcing .js files with a dot ..
Other Known
.js shells
- nshell
- nsh
- shelljs`