execline
Software
skarnet.org

# The `execlineb` program

`execlineb` reads and executes a script.
It is a command launcher: it reads a file, turns that file into a command line, then executes into that command line.

## Interface

         execlineb [ -q | -w | -W ] [ -p | -P | -S nmin | -s nmin ] [ -e ] -c script [ args... ]

or

         execlineb [ -q | -w | -W ] [ -p | -P | -S nmin | -s nmin ] [ -e ] scriptfile [ args... ]

or in an executable file:

    #!/command/execlineb [ -qwWpPSnmin ]
    script

Parsing phase.

- `execlineb` reads and parses the script it is given. It exits 100 on a syntax error and 111 on a temporary error. It makes an argv, i.e. a system command line, with the parsed script. If the argv is empty, `execlineb` exits 0.

Environment management phase.

- Pushing the current stack frame. If none of the `-p`, `-P`, `-S` or `-s` options are set: `execlineb` pushes the current positional parameters, i.e. environment variables that start with `#`, `0`, `1`, ..., `9`. To get the previous values back, use `emptyenv -P`.
- Setting the new stack frame. If none of the `-P`, `-S` or `-s` options are set:
  - `execlineb` sets the `#` environment variable to the number n of args it is given.
  - It sets the `0` environment variable to the name of the script - or to the `execlineb` invocation name if the `-c` option is used.
  - It sets the `1`, `2`, ... `n` environment variables to the different args.

Execution phase.

- `execlineb` executes into the argv it has built from the script. There is only one command line for the whole script: the `execlineb` binary is a launcher, whose sole purpose is to execute into that command line. It does not stay in memory like a traditional interpreter would.

## Options

- `-e` : this option is ignored. This is meant to support the use of execlineb in conjuction with programs that invoke `$SHELL -ec script`; the effect of `/bin/sh -e` can be natively replicated in execline scripts if you use the if command instead of the foreground command.
- `-c script` : execute script, do not look for a file.

See below for the other options.

## Syntax of scripts

An execlineb script is a string that must not contain the null character. `execlineb` parses it and divides it into words. The parser recognizes the following components:

- whitespace is defined as spaces, tabs, newlines and carriage returns. Words are always separated by whitespace.
- A quoted string begins with a doublequote (`"`) and ends with another doublequote. Quoted doublequotes must be prefixed by a backslash (`\`). Quoted strings always evaluate to exactly one word. For instance, `""` evaluates to the empty word.
- The `\a`, `\b`, `\t`, `\n`, `\v`, `\f`, and `\r` sequences are recognized in quoted strings, and are converted to the ASCII numbers 7, 8, 9, 10, 11, 12 and 13 respectively.
- Inside a quoted string, backslashed newlines disappear completely.
- `\0xab` sequences are recognized in quoted strings and evaluate to ASCII hexadecimal number ab.
- `\0abc` sequences are recognized in quoted strings and evaluate to ASCII octal number abc. abc must not be greater than 377, or evaluate to 0.
- `\abc` sequences are recognized in quoted strings and evaluate to ASCII decimal number abc. a must not be zero. abc must not be greater than 255, or evaluate to 0.
- A comment starts with a `#` and ends with the line. Comments are not recognized inside quoted strings.
- Anything else is an unquoted string, that can evaluate to zero or more words.
- Any character can be escaped in unquoted strings by prepending it with a backslash. It works the same way in quoted strings, except for the special sequences described above.
- As a special case, an unquoted backslash at the end of a line, or at the end of the input, is ignored. This is to make it easier to copy execline fragments from a shell script.

You can see an example of distinct `execlineb` components here.

In addition to that simple lexing, `execlineb` performs the following higher-level parsing:

- A word consisting of a single opening brace (`{`) increments an internal level counter, blevel, and disappears from the argv. Quoted open braces do not have that behaviour.
- A word consisting of a single closing brace (`}`) decrements blevel, and is replaced with the empty word. Quoted closing braces do not have that behaviour.
- If `execlineb` finds that braces are unmatched (i.e. blevel goes below 0 during the parsing, or is not 0 at the end of the script), it exits 100 with an error message.
- `execlineb` automatically quotes blocks. Which means that every time it finds a word, it prepends it with blevel spaces.

For proper execution, the sequence of words must follow the execline grammar.

## Options for block syntax checking

External execline commands that read blocks, like foreground, use the `EXECLINE_STRICT` environment variable: if it is set to 1, they will print a warning message on stderr if they find their blocks not to be properly quoted. If it is set to 2, they will also die. If it is set to 0, or unset, they won't complain at all.

Normally the `EXECLINE_STRICT` environment variable is inherited from the caller. You can force it unset, set to 1, or set to 2 by giving respectively the `-q`, `-w` or `-W` option to `execlineb`.

The `EXECLINE_STRICT` variable (as well as the `-q`, `-w` and `-W` options to `execlineb`) will also modify the behaviour of the `-S nmin` and `-s nmin` options when `execlineb` is called with less than nmin positional parameters:

- If `EXECLINE_STRICT` is 0: the script will run silently, and missing positional parameters, up to nmin, will be substituted with the empty word.
- If `EXECLINE_STRICT` is 1 or unset: same, but the script will print a warning message rather than run silently.
- If `EXECLINE_STRICT` is 2: the script will exit with an error message.

## Options for environment management

Normally, execline scripts are reentrant: environment variables potentially overwritten by `execlineb`, such as `#` or `0`, are pushed. This is the standard, safe behaviour. Nevertheless, it is rather costly, and may be unneeded for small scripts: for those cases, execline comes with two options that bypass the environment management. Be warned that the purpose of these options is optimization, and you should not use them if you're not familiar with the way execlineb uses the environment to store positional parameters. Alternatively, there's also an integrated substitution mechanism that doesn't make use of the environment at all.

- The `-p` option will bypass the push phase: the current frame of positional parameters will be overwritten. The script will not be reentrant.
- The `-P` option will bypass positional parameter handling completely: the environment will not be pushed, and positional parameters will be ignored. `execlineb -P -c "script"` is equivalent to, but more efficient than, `execlineb -c "emptyenv -P script"`. You should use the `-P` option only in standalone scripts that take no arguments, such as s6's or runit's run scripts.
- The `-S nmin` option will substitute the positional parameters - up to at least nmin - but will not push nor set environment variables. `execlineb -S3 -c "script"` is equivalent to, but more efficient than, `execlineb -c "elgetpositionals -P3 emptyenv -P script"`. See the details.
- The `-s nmin` option behaves just like the `-S` option, except that it defines `$@` as the rest of the command line after nmin arguments have been removed.

## Current limitations

`execlineb` builds and executes a unique argv with the script: hence scripts are subject to OS-dependent limitations such as the kernel buffer size for argv and envp - at least 64 kB on most systems. This means that `execlineb` cannot execute arbitrarily large scripts. Be careful with deeply nested scripts too: without the `-p`/`-P`/`-S`/`-s` option, each execlineb invocation uses up some space in the environment.