This is a proof-of-concept interactive REPL for Laurent Bercot's execline language.
execshell depends on the skalibs and execline libraries for the
execlineb interpreter's lexing functionality, and the linenoise library for
line editing functionality.
A fork of linenoise which includes UTF-8 line editing support is included
in this repository as a submodule, so the following commands are required when
cloning:
$ git clone https://github.com/sysvinit/execshell
$ cd execshell
$ git submodule update --init
A Makefile is provided for compiling the execshell sources, which should be
sufficient for building the project. Please note that the Makefile assumes that
you have the libskarnet and libexecline libraries installed within your system
linker's default search path.
execshell provides an interactive interface with
readline/Emacs-alike line editing to the command lexer used by the
execlineb script
launcher. For example:
$ ./execshell
> foreground { echo foo } echo bar
foo
bar
> pipeline { echo baz } sed -e "s/a/u/" -e "s/$/z/"
buzz
(Note that the prompt string here is > .)
execshell has a single builtin command: self. If a command line is
prefixed with this token, then the command runner process will append its own
argv[0] to the command line before executing into it. This can be used for
modifying the REPL's own execution environment (such as changing directory and
manipulating environment variables). For example:
$ # PATH manipulation needed to make self re-execution work after changing directory
$ PATH=$PWD:$PATH execshell
> pwd
/home/molly/src/pub/execshell
> # execline's cd command needs a program to exec into
> cd /home/molly
execline-cd: usage: cd path prog...
> self cd /home/molly
> pwd
/home/molly
The REPL also has rudimentary signal handling, so control-C should hopefully
deliver SIGINT to the foreground process without killing the REPL, however
this has only had cursory testing.
execshell is split into two processes, a supervisor parent and a command
runner process. At startup, the supervisor forks the command runner, and then
restarts it if it exists with a non-zero exit code. The command runner then
handles reading input from the terminal, lexing command inputs, and running
commands in child processes of its own. The parent exits if the child exits
with a zero exit code, or is terminated by a signal.
The rationale for this split process model is to make the implementation of the
self builtin a little more robust. The command runner executes directly into
the given command when the self token is given, and it's possible that this
command may not succeed, and might fail to execute back into execshell. If
this were implemented all within a single process, then this could lead
to typos in commands causing execshell to unexpectedly exit, which is
undesirable. Hence, the supervisor process is used to restart the child process
when the latter unexpectedly exits with an error.
execshell is Copyright (C) 2020 Molly Miller under the ISC licence. Please
see the LICENSE file for the full licence text.
The linenoise library is a separate project, which is licensed under the
2-clause BSD licence.