SEES JavaScript shell interpreter

This program can be interesting for you if you want to write shell scripts on Unix-like platforms – but in JavaScript instead of “sh” (bourne/bash/csh and the like). All you need to know are the JavaScript basics and the usual suspects among the console commands that you often use in the shell window (e.g. “cd”, “mv”, “cp”). To see the differences and similarities, risk a glance at these shell script codes:

Bash

#!/bin/sh
cd ~/Desktop
echo Hello world

pwd
ls *.txt
source otherscript.sh

c=1
while [ $c -le 5 ]; do
	echo "Welcome $c times"
	(( c++ ))
done

if [ -f $1 ]; then
	echo "$1 is a file"
else
	echo "$1 is no file" 1>&2
	exit 1
fi

JavaScript

#!/usr/bin/sees
cd("~/Desktop");
alert("Hello world");

alert(pwd());
alert(ls("*.txt"));
include("otherscript.js");

var c=1;
while(c <= 5) {
	alert("Welcome " + c + " times");
	c++;
}

if(isfile(args[1])) {
	alert(args[1] + " is a file");
} else {
	throw args[1] + " is no file";
	// exit(1) is not required
}


As you can see, the basic approach of SEES is implementing JavaScript code similar to the normal shell scripting. The functions you often need are in the global scope and not hidden in objects and sub-objects. JavaScript has also advantages if you write mode complex code – however, for small and mainly sequential scripts (like one if, three cp and one cd), the bash is still the tool you want to use.

Download and use

A binary is available for MacOS 10.6, you can download it here. There is explicitly no MacOS installer for it, as I don”t see a point to copy one single file to a binary directory if you possibly even don”t want this. This is a freeware program and comes without any warranties.

Run without installation

To run a JavaScript like a shell script with SEES from a folder you want, just do the following steps. These are actually almost the same steps when you create a bash script:

  1. Copy sees to this folder
  2. Create a JavaScript file in the folder (e.g. script.js)
  3. Make the JavaScript file executable using chmod 711 script.js
  4. Put #!/.sees in the first line of the script
  5. Thats it, you can implement your code, e.g. echo("Hello world!");
  6. Run your script by typing ./script.js in the shell window

Install SEES

Simply copy the sees binary file to the /usr/bin directory and give it the right access permissions:

  1. Copy: sudo cp sees /usr/bin
  2. Owner: sudo chown root:wheel /usr/bin/sees
  3. Permissions: sudo chmod 711 /usr/bin/sees

Some Annotations

  1. The “.js” file extension is not required for the interpreter. If your script shall look like a command, just name it with out an extension – like dosomething
  2. You can make an additional private binary path where you put your scripts in:
    1. Create a new folder somewhere in your home directory, example: mkdir ~/.bin (this .bin folder will not be displayed in the Finder)
    2. Open the file ~/.bash_profile and add the line export PATH=$PATH:~/.bin. If it is not yet in your home folder, create it
    3. If your terminal program is open, quit the process (in the Dock, not only the windows) and reopen it to make the changes being reloaded
    4. Put your script files into your ~/.bin folder
    5. Now you can call your programs from everywhere you like

Source code version

You can compile the sees-source for other Unix-like platforms using the GCC (I used GCC4.2.1). The zip contains a NetBeans project that should compile without changes (I have to admit that I still didn”t get it managed to create an autoconf project out of it, so if you have time and the proper toolbox installed on your machine – I would be glad :-) ).

More about it …

The shell interpreter is based on the Simple ECMAScript Engine (SEE), which is written by David Leonard and published under GPL compatible BSD license. SEE is a very slim and well functioning open-source JavaScript interpreter, which can be integrated in c/c++ projects. So SEES is “SEE for the Shell”, uses the SEE library, sticks to the same license, and hence is an open-source project.

Synopsis

 sees [-options] <script file> [<script arg1> [<script arg1> [...]]] 

Libraries

You can write your own JavaScript libraries. The program will execute the following script files in the given order, if they exist:

  1. /etc/sees/library.js
  2. /Library/Application Support/sees/library.js
  3. ~/.sees_library.js
  4. ~/Library/Application Support/sees/library.js

All functions and variables you define in your library are available in all your scripts, as long you do not call sees with the switch "--no-library", e.g. #!/usr/bin/sees --no-library. Note that you can overload variables and functions. If the function foo() {} is implemented in /etc/sees/library.js and in ~/.sees_library.js, then the foo() will do what ~/.sees_library.js says.

Short how-to

The most comments are posted in the blog category SEES, but here some basics in place.

Reading text from a file

Here we use the function that we know from the shell: cat:

alert("The text in the file is=" + cat("textfile.txt") );

Writing text in a file

As echo text > file is used in bash, the alert/print/echo functions have two optional parameters:

alert("My text", "~/textfile.txt"); // Replace the file if it exists
alert("My text", "~/textfile.txt", true); // Append text to the file if it exists

Command line arguments

Arguments are stored in the args[] array. Like using the bash, the first parameter args[0] is the program name/path. To test this script, call it with the command line somehow like ./script argument1 "argument 2" and other arguments.

alert("I am the script " + args[0] + ", and these are my arguments:");
for(var i=1; i < args.length; i++) {
  alert(" args[" + i + "] = " + args[i]);
}

Input from pipes

You can input text from pipes, like cat file.txt | myscript.js. If you do so, then the content of the text file, which was passed to your script, will be stored in the variable stdin.

alert("I've got something from a pipe here:" + stdin);

Troubleshooting

  1. Interpreter throws a parse error: Make sure that your script is saved in UTF8, because you have probably some special characters in it like the German “ä”, the French “é”, the Spanish “ñ” or wherever you implement :-)

Reference of build-in objects, functions and variables

What you see below is a copy of the language extensions you get when you type sees --help. All the functions are explained with argument types, and the obligatory brackets [ ] for optional parameters.

Global variables

var String stdin
  Contains the standard input passed to the script, e.g. by piping like
  cat file.txt | script.js

var Array args
  Contains the command line arguments passed to the script, e.g.
  script.js -switch1 "Text argument 2" argument3
  The first argument is always the script name (or what command you typed,
  e.g. "./script.js" or "~/scripts/script.js"

Core extension functions and objects

function sh(String <command>)
   Executes a shell command, writes stdout and stderr to the console and
   returns the exit code.

function exec(String <command>, [Double <timeout in s>, String <stdin text>])
   Executes a program and returns the exit code, the standard output and the
   error output of the program as object. You can set a program timeout in
   seconds and pass a text to the stdin pipe of the program.
   Other than using function sh(), this function cannot evaluate shell
   redirections like "echo Any test > file.txt" or "cat file.txt 2>1".
   Instead, the results are saved in the object:

   Object {
	 String stdout
	 String stderr
	 Integer exitcode
   }

function print(String <text>, [String <file path>, Boolean <append=false>])
   Prints the texts to the console standard output. If <file path> is
   specified, the output is redirected to a file. Optionally the output
   is appended at the end of the file
   Returns nothing

function println(String <text>, [String <file path>, Boolean <append=false>])
   Prints the texts to the console standard output and adds a new line
   If <file path> is specified, the output is redirected to a file. Optionally
   the output is appended at the end of the file
   Returns nothing

function alert(String <text>, [String <file path>, Boolean <append=false>])
   Prints the texts to the console standard output and adds a new line
   (JavaScript known alias of println). If <file path> is specified, the
   output is redirected to a file. Optionally the output is appended at the
   end of the file.
   Returns nothing

function include(String <path to JavaScript file>)
   Executes a JavaScript. All variables and functions exists after the
   include has finished (which allows you to write libraries. As the
   import keyword is reserved and may be used later for explicit library
   loading, we use include to load any file we want in the file system.)
   Returns nothing

function exit(Integer <return code> )
   Returns to the parent process with a spacified exit code

function env(String <variable>, [String <new value>])
   Gets or sets the value of an environment variable
   In both cases the actual value of the variable is returned

Object sees {

   The object contains interpreter specific functions and data:

   function compatibility()
	  Returns the interpreter JavaScript compatibility integer

   function version()
	  Returns the program version as double

   function gc()
	  Runs the SEE garbage collector
	  Returns nothing

   function gcdump()
	  Dumps the SEE garbage collector
	  Returns nothing

   function help()
	 Returns a string containing this help text

}

Shell-command (bash) derived functions

function echo(String <text>, [String <file path>, Boolean <append=false>])
   Prints the texts to the console standard output and adds a new line
   (Bash known alias of println). If <file path> is specified, the output is
   redirected to a file. Optionally the output is appended at the end of the
   file.
   Returns nothing

function ls(String <dir/pattern>, [Boolean <show hidden>, Boolean <recursive>])
   Lists directory contents (like shell command ls) If you search for hidden
   files (e.g. ls(".*")), then <show hidden> is automatically switched on.
   Returns an Array with file and directory names

function cd(String <directory>)
   Changes the current working directory (like shell command cd)
   Returns a String which contains the new directory

function cwd()
   Returns a String which contains the current working directory
   (like shell command cwd)

function pwd()
   Returns a String which contains the current working directory
   (like shell command cwd)

function mv(String <directory/file>, String <new location>)
   Moves a file or directory like the mv shell command
   Returns (nothing)

function cp(String <directory/file>, String <directory/file>)
   Copys a file or directory like the cp shell command
   Returns (nothing)

function ln(String <file/dir path>, String <link path>, [Boolean <hardlink>])
   Creates a symbolic link or hard link to a file or directory.
   Note that hard links to directories are normally forbidden.
   Returns (nothing)

function rm(String <file>)
   Deletes a file like the rm shell command
   Returns (nothing)

function rmdir(String <directory>)
   Deletes an empty directory like the rmdir shell command
   Returns (nothing)

function unlink(String <file>)
   Deletes a file or directory like the rm shell command
   The function is an alias for rm()
   Returns (nothing)

function mkdir(String <directory>)
   Creates a directory with the permissoin 755
   Returns (nothing)

function chmod(String <file/directory>, [Integer <permissions>])
   Gets or sets the value of file permissions
   The permissions can be set as string or integer, e.g. "777" or 711
   In both cases the actual permission of the file is returned

function chown(String <file/directory>, [String <owner>])
   Gets or sets the file owner
   In both cases the actual owner of the file is returned

function chgrp(String <file/directory>, [String <group>])
   Gets or sets the file group
   In both cases the actual group of the file is returned

function touch(String <file/directory>, [<modification time>, <access time>])
   Sets new modification and access time of a file. If <modification time>
   of <access time> is not specified, the time is unchanged. If the file does
   not exist, an empty regular file is created. The data types of the times
   can be a UNIX timestamp, a Date object, or a string string (see date formats
   section

function cat(String <file/directory>)
   Returns the content of a file

function md5(String <file>)
   Returns a String which contains the md5 checksum of a given path

function kill(Integer <PID>, [Boolean <immediately=false>])
   Stops a running process by sending the signal SIGTERM. If the
   argument <immediately> is true, the signal SIGKILL is sent, which is
   not blockable. Use this parameter only if a process does not respond.

function basename(String <directory/file>)
   Returns a String which contains the basename of a given path

function dirname(String <directory/file>)
   Returns a String which contains the directory of a given path

Shell related functions which have not the same name as bash commands

function exist(String <path>, [boolean <dont't follow symlinks=false>])
   Returns true if the <path> exists, else false
   The function follows symlinks if second argument is not true.

function isfile(String <path>)
   Returns true if <path> is a file, else false
   The function always follows symlinks

function isdir(String <path>)
   Returns true if <path> is a directory, else false
   The function always follows symlinks

function islink(String <path>)
   Returns true if <path> is a symbolic link, else false
   The function never follows symlinks

function filesize(String <path>)
   Returns the file size of <path> in bytes

function filectime(String <path>, [Boolean <dont' follow symlinks>])
   Returns the file creation time of <path> as Date object

function filemtime(String <path>, [Boolean <dont' follow symlinks>])
   Returns the file modification time of <path> as Date object

function fileatime(String <path>, [Boolean <dont' follow symlinks>])
   Returns the file access time of <path> as Date object

function tmpfile()
   Returns the path to a usable temporary file in the /tmp directory

function sha1(String <file>)
   Returns a String which contains the sha1 checksum of a given path
   The function is similar to 'shasum -a 1 <path>'

function sha256(String <file>)
   Returns a String which contains the sha256 checksum of a given path
   The function is similar to 'shasum -a 256 <path>'

function sha384(String <file>)
   Returns a String which contains the sha384 checksum of a given path
   The function is similar to 'shasum -a 384 <path>'

function sha512(String <file>)
   Returns a String which contains the sha512 checksum of a given path
   The function is similar to 'shasum -a 512 <path>'

Object extensions

String.prototype.trim()
   Returns a String with spaces, tabs and newline characters chopped at the
   beginning and end of the text.

String.prototype.ltrim()
   Returns a String with spaces, tabs and newline characters chopped at the
   beginning of the text.

String.prototype.rtrim()
   Returns a String with spaces, tabs and newline characters chopped at the
   end of the text.

Comments are closed.