From f316a2ed52195135a35e32d7096e876357c48c69 Mon Sep 17 00:00:00 2001 From: Laurent Bercot Date: Thu, 18 Sep 2014 20:03:23 +0000 Subject: initial commit: rc for execline-2.0.0.0 --- doc/background.html | 57 +++++++++ doc/backtick.html | 66 ++++++++++ doc/cd.html | 45 +++++++ doc/componentsb.txt | 41 ++++++ doc/define.html | 42 +++++++ doc/dieshdiedie.html | 278 +++++++++++++++++++++++++++++++++++++++++ doc/dollarat.html | 86 +++++++++++++ doc/el_pushenv.html | 173 ++++++++++++++++++++++++++ doc/el_semicolon.html | 124 +++++++++++++++++++ doc/el_substitute.html | 309 ++++++++++++++++++++++++++++++++++++++++++++++ doc/el_transform.html | 204 ++++++++++++++++++++++++++++++ doc/elgetopt.html | 60 +++++++++ doc/elgetpositionals.html | 94 ++++++++++++++ doc/elglob.html | 68 ++++++++++ doc/emptyenv.html | 57 +++++++++ doc/exec.html | 50 ++++++++ doc/execline-shell.html | 53 ++++++++ doc/execline-startup.html | 59 +++++++++ doc/execlineb.html | 246 ++++++++++++++++++++++++++++++++++++ doc/exit.html | 44 +++++++ doc/export.html | 43 +++++++ doc/fdblock.html | 55 +++++++++ doc/fdclose.html | 44 +++++++ doc/fdmove.html | 55 +++++++++ doc/fdreserve.html | 92 ++++++++++++++ doc/forbacktickx.html | 77 ++++++++++++ doc/foreground.html | 57 +++++++++ doc/forx.html | 66 ++++++++++ doc/getpid.html | 44 +++++++ doc/grammar.html | 160 ++++++++++++++++++++++++ doc/heredoc.html | 56 +++++++++ doc/homeof.html | 37 ++++++ doc/if.html | 68 ++++++++++ doc/ifelse.html | 59 +++++++++ doc/ifte.html | 67 ++++++++++ doc/ifthenelse.html | 59 +++++++++ doc/import.html | 37 ++++++ doc/importas.html | 57 +++++++++ doc/index.html | 213 ++++++++++++++++++++++++++++++++ doc/loopwhilex.html | 60 +++++++++ doc/multidefine.html | 69 +++++++++++ doc/multisubstitute.html | 121 ++++++++++++++++++ doc/pipeline.html | 67 ++++++++++ doc/piperw.html | 38 ++++++ doc/quine-dam.txt | 110 +++++++++++++++++ doc/quine-jriou.txt | 28 +++++ doc/quine-prj-2.txt | 15 +++ doc/quine-prj-3.txt | 13 ++ doc/quine-prj.txt | 13 ++ doc/redirfd.html | 100 +++++++++++++++ doc/runblock.html | 75 +++++++++++ doc/shift.html | 68 ++++++++++ doc/tryexec.html | 67 ++++++++++ doc/umask.html | 44 +++++++ doc/unexport.html | 46 +++++++ doc/upgrade.html | 35 ++++++ doc/wait.html | 53 ++++++++ 57 files changed, 4524 insertions(+) create mode 100644 doc/background.html create mode 100644 doc/backtick.html create mode 100644 doc/cd.html create mode 100644 doc/componentsb.txt create mode 100644 doc/define.html create mode 100644 doc/dieshdiedie.html create mode 100644 doc/dollarat.html create mode 100644 doc/el_pushenv.html create mode 100644 doc/el_semicolon.html create mode 100644 doc/el_substitute.html create mode 100644 doc/el_transform.html create mode 100644 doc/elgetopt.html create mode 100644 doc/elgetpositionals.html create mode 100644 doc/elglob.html create mode 100644 doc/emptyenv.html create mode 100644 doc/exec.html create mode 100644 doc/execline-shell.html create mode 100644 doc/execline-startup.html create mode 100644 doc/execlineb.html create mode 100644 doc/exit.html create mode 100644 doc/export.html create mode 100644 doc/fdblock.html create mode 100644 doc/fdclose.html create mode 100644 doc/fdmove.html create mode 100644 doc/fdreserve.html create mode 100644 doc/forbacktickx.html create mode 100644 doc/foreground.html create mode 100644 doc/forx.html create mode 100644 doc/getpid.html create mode 100644 doc/grammar.html create mode 100644 doc/heredoc.html create mode 100644 doc/homeof.html create mode 100644 doc/if.html create mode 100644 doc/ifelse.html create mode 100644 doc/ifte.html create mode 100644 doc/ifthenelse.html create mode 100644 doc/import.html create mode 100644 doc/importas.html create mode 100644 doc/index.html create mode 100644 doc/loopwhilex.html create mode 100644 doc/multidefine.html create mode 100644 doc/multisubstitute.html create mode 100644 doc/pipeline.html create mode 100644 doc/piperw.html create mode 100644 doc/quine-dam.txt create mode 100644 doc/quine-jriou.txt create mode 100644 doc/quine-prj-2.txt create mode 100644 doc/quine-prj-3.txt create mode 100644 doc/quine-prj.txt create mode 100644 doc/redirfd.html create mode 100644 doc/runblock.html create mode 100644 doc/shift.html create mode 100644 doc/tryexec.html create mode 100644 doc/umask.html create mode 100644 doc/unexport.html create mode 100644 doc/upgrade.html create mode 100644 doc/wait.html (limited to 'doc') diff --git a/doc/background.html b/doc/background.html new file mode 100644 index 0000000..85d2589 --- /dev/null +++ b/doc/background.html @@ -0,0 +1,57 @@ + + + + + execline: the background command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The background program

+ +background launches a command in the background, then goes on +with the execution flow. + +

Interface

+ +

+ In an execlineb script: +

+ +
+     background [ -d ] { prog1... } prog2...
+
+ + + +

Options

+ + + +

Notes

+ + + + + diff --git a/doc/backtick.html b/doc/backtick.html new file mode 100644 index 0000000..7bdc037 --- /dev/null +++ b/doc/backtick.html @@ -0,0 +1,66 @@ + + + + + execline: the backtick command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The backtick program

+ +

+backtick runs a program and uses its output as the argument of +another program. +

+ +

Interface

+ +

+ In an execlineb script: +

+ +
+     backtick [ -i ] [ -n ] variable { prog1... } prog2...
+
+ + + +

Options

+ + + +

Notes

+ + + + + diff --git a/doc/cd.html b/doc/cd.html new file mode 100644 index 0000000..416dc42 --- /dev/null +++ b/doc/cd.html @@ -0,0 +1,45 @@ + + + + + execline: the cd command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The cd program

+ +

+cd changes the current working directory to a +given directory, then executes a program. +

+ +

Interface

+ +
+     cd dir prog...
+
+ +

+cd performs a +chdir() +system call on dir, then execs into prog.... +

+ +

Notes

+ +

+cd is a standard shell builtin. Be careful if you want to +use the cd command outside of an execline script. +

+ + + diff --git a/doc/componentsb.txt b/doc/componentsb.txt new file mode 100644 index 0000000..a191f04 --- /dev/null +++ b/doc/componentsb.txt @@ -0,0 +1,41 @@ +#!/command/execlineb + +# This execlineb script will sleep for 1 second, then print some +# silly things on the standard output. + + +foreground # an unquoted string, evaluated to: foreground +{ # A single opening brace, not included in the argv + sleep 1 # Two unquoted strings, evaluated to " sleep" and " 1" + # (without the quotation marks). +} # A single closing brace, evaluated to the empty word + +"echo" # this is a quoted string. It will evaluate to the word: echo + +foo\ bar\ zoinx # This is one word, since the spaces are escaped +"foo bar zoinx" # This is exactly the same word, written another way + + " # this is not a comment, since it is inside a quoted string +# This is not a comment either \" # nor is this " # but this is one + +"\0x41\66\0103D\n" # This is the string ABCD followed by a newline. + # Be careful: the newline will be part of the word. + + \n # this is not a newline, but the single word: n + +$23 # This will NOT be replaced by anything with execline-1.y, unless + # substitution is explicitly asked for in the script. + # The dollar is no special character for the execline binary. + +baz"$1"qux # This will evaluate to the word baz$1qux +baz\$1qux # Same here +baz$1qux # Same here in execline-1.y + +${PATH} # This will NOT be replaced by execline ; use the import command + # if you need the $PATH value. + +'this is not a string' # it will be parsed as five separate words + +"\ +" # This will be parsed as the empty word. A (backslash, newline) + # sequence inside a quoted string is entirely removed. diff --git a/doc/define.html b/doc/define.html new file mode 100644 index 0000000..4d5e0f2 --- /dev/null +++ b/doc/define.html @@ -0,0 +1,42 @@ + + + + + execline: the define command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The define program

+ +

+define replaces a literal with a value, then executes +another program. +

+ +

Interface

+ +
+     define [ -s ] [ -C | -c ] [ -n ] [ -d delim ] variable value prog...
+
+ + + + + diff --git a/doc/dieshdiedie.html b/doc/dieshdiedie.html new file mode 100644 index 0000000..dc3c661 --- /dev/null +++ b/doc/dieshdiedie.html @@ -0,0 +1,278 @@ + + + + + execline: why execline and not sh + + + + + + +execline
+Software
+skarnet.org

+ +

Why not just use /bin/sh ?

+ + + +

Security

+ +

+ One of the most frequent sources of security problems in programs +is parsing. Parsing is a complex operation, and it is easy to +make mistakes while designing and implementing a parser. (See +what Dan Bernstein says +on the subject, section 5.) +

+ +

+ But shells parse all the time. Worse, the essence +of the shell is parsing: the parser and the runner are intimately +interleaved and cannot be clearly separated, thanks to the +specification. +Even worse, the +shell sometimes has to perform double parsing, for instance +after parameter expansion. This can lead to atrocities like +

+zork="foo ; echo bar"
+touch $zork
+
not doing what you would like them to do, even in that simple +case. (zsh has a sane behaviour by +default, at the expense of explicitly breaking the spec.) +

+ +

+execlineb parses the script only once: when +reading it. The parser has been designed to be simple and systematic, +to reduce the potential for bugs - which you just cannot do +with a shell. After execlineb has split up the script into +words, no other parsing phase will happen, unless the user explicitly +requires it. Positional parameters, when +used, are never split, even if they contain spaces or newlines, unless +the user explicitly requires it. Users control exactly what +is split, what is done, and how. +

+ + +

Portability

+ +

+ The shell language was designed to make scripts portable across various +versions of Unix. But it is actually really hard to write a portable shell +script. There are dozens of distinct +sh flavours, not even counting the openly incompatible +csh approach and its various tcsh-like followers. +The ash, bash, ksh and zsh shells +all exhibit a different behaviour, even when they are +run with the so-called compatibility mode. From what I have +seen on various experiments, only zsh is able to follow the +specification to the letter, at the expense of being big and complex to +configure. This is a source of endless problems for shell script writers, +who should be able to assume that a script will run everywhere, +but cannot in practice. Even a simple utility like test +cannot be used safely with the normalized options, because most shells +come with a builtin test that does not respect the +specification to the letter. And let's not get started about echo, +which has its own set of problems. Rich Felker has +a page listing tricks +to use to write portable shell scripts. Writing a portable script should +not be that hard. +

+ +

+execline scripts are portable. There is no +complex syntax with opportunity to have an undefined or nonportable +behaviour. The execline package is portable across platforms: +there is no reason for vendors or distributors to fork their own +incompatible version. + Scripts will +not break from one machine to another; if they do, +it's not a "portability problem", it's a bug. You are then encouraged +to find the program that is responsible for the different behaviour, +and send a bug-report to the program author - including me, if the +relevant program is part of the execline distribution. +

+ +

+ A long-standing problem with Unix scripts is the shebang line, which +requires an absolute path to the interpreter. Scripts are only portable +as is if the interpreter can be found at the same absolute path on every +system. With /bin/sh, it is almost the case (Solaris +manages to get it wrong by having a non-POSIX shell as /bin/sh +and requiring something like #!/usr/xpg4/bin/sh to get a POSIX +shell to interpret your script). Other scripting languages are not so +lucky: perl can be /bin/perl, /usr/bin/perl, +/usr/local/bin/perl or something else entirely. For those cases, +some people advocate the use of env: #!/usr/bin/env perl. +But first, env can only find interpreters that can be found via the +user's PATH environment variable, which defeats the purpose of having an +absolute path in the shebang line in the first place; and second, this only +displaces the problem: the env utility does not +have a guaranteed absolute path. /usr/bin/env is the usual +convention, but not a strong guarantee: it is valid for systems to have +/bin/env instead, for instance. +

+ +

+execline suffers from the same issues. #!/bin/execlineb ? +#!/usr/bin/execlineb ? This is the only portability problem that +you will find with execline, and it is common to every script language. +

+ +

+ The real solution to this portability problem is a convention that +guarantees fixed absolute paths for executables, which the FHS does not do. +The slashpackage convention is +such an initiative, and is well-designed; but as with every +convention, it only works if everyone follows it, and unfortunately, +slashpackage has not +found many followers. Nevertheless, like every skarnet.org package, execline +can be configured to follow the slashpackage convention. +

+ + +

Simplicity

+ +

+ I originally wanted a shell that could be used on an embedded system. +Even the ash shell seemed big, so I thought of writing my +own. Hence I had a look at the +sh +specification... and ran away screaming. +This specification +is insane. It goes against every good programming +practice; it seems to have been designed only to give headaches +to wannabe sh implementors. +

+ +

+ POSIX cannot really be blamed for that: it only normalizes existing, historical +behaviour. One can argue whether it is a good idea to normalize atrocious +behaviour for historical reasons, as is the case with the infamous +gets +function, but this is the way it is. +

+ +

+ The fact remains that modern shells have to be compatible with that historical +nonsense and that makes them big and complex at best, or incompatible and ridden +with bugs at worst. +An OpenBSD developer said to me, when asked about the OpenBSD /bin/sh: +"It works, but it's far from not being a nightmare". +

+ +

+ Nobody should have +nightmare-like software on their system. Unix is simple. Unix +was designed to be simple. And if, as Dennis Ritchie said, "it takes a +genius to understand the simplicity", that's because incompetent people +took advantage of the huge Unix flexibility to write insanely crappy or +complex software. System administrators can only do a decent job when +they understand how the programs they run are supposed to work. People +are slowly starting to grasp this (or are they ? We finally managed +to get rid of sendmail and BIND, but GNU/Linux users seem happy to +welcome the era of D-Bus and systemd. Will we ever learn ?) - but even +sh, a seemingly simple and basic Unix program, is hard to +understand when you lift the cover. +

+ +

+ So I decided to forego sh entirely and take a new approach. So far it +has been working. + The execline specification is simple, and, +as I hope to have shown, easy to implement without too many bugs or +glitches. +

+ + +

Performance

+ +

+ Since it was made to run on an embedded system, execline was +designed to be light in memory usage. And it is. +

+ + + +

+ You can have hundreds of execline scripts running simultaneously on an +embedded box. Not exactly possible with a shell. +

+ +

+ For scripts than do not require many computations that a shell can do +without calling external programs, + execline is faster than the shell. +Unlike sh's +one, the execline parser is simple and +straightforward; actually, it's more of a lexer than a parser, because +the execline language has been designed to be LL(1) - keep it simple, +stupid. +execline scripts get analysed and launched practically without a delay. +

+ + + + + +

execline limitations

+ + + + + diff --git a/doc/dollarat.html b/doc/dollarat.html new file mode 100644 index 0000000..2c09592 --- /dev/null +++ b/doc/dollarat.html @@ -0,0 +1,86 @@ + + + + + execline: the dollarat command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The dollarat program

+ +

+dollarat prints the positional parameters of an execline script. +

+ +

Interface

+ +
+     dollarat [ -n ] [ -0 | -d delimchar ]
+
+ + + +

Options

+ + + +

Notes

+ + + + + diff --git a/doc/el_pushenv.html b/doc/el_pushenv.html new file mode 100644 index 0000000..2ae16dd --- /dev/null +++ b/doc/el_pushenv.html @@ -0,0 +1,173 @@ + + + + + execline: pushing and popping the environment + + + + + + +

+execline
+Software
+skarnet.org +

+ +

Pushing and popping the environment

+ +

+ The execlineb launcher +can store positional +parameters, i.e. arguments given to your script, into the +environment. The # variable contains the number of arguments; +the 0 variable contains the name of your execline script; +the 1 variable contains the first argument; and so on. +

+ +

+ Up to execline-1.04, this could create problems with nested scripts: +the inner script would overwrite the outer script's parameters, and +there was no way to get them back. In particular, writing execline +commands in the execline language via the +runblock command was impossible. +

+ + + +

+ To solve that issue, execline now implements a kind of environment +stack. When execlineb reads the arguments, it does +not overwrite the positional parameters, but pushes them on a +stack: +

+ + + +

+ Same goes for the other positional parameters. +

+ +

+ The script then runs; and commands such as +elgetpositionals use the current +frame of positional parameters, without paying attention to the deeper +levels. +

+ + + +

+ When you are done with the arguments, it is advisable to drop +the current frame, and pop the environment stack to get it back +to its previous state: +

+ + + +

+ Again, same goes for the other positional parameters.
+The
runblock command will perform that +pop operation automatically; the standard "manual" way to +perform it is to use the emptyenv -P command. +

+ +

A pop example

+ +

+ Suppose you want to run the long-lived program prog after +printing the list of its arguments. +

+ +
+ #!/command/execlineb
+ elgetpositionals
+ foreground { echo $0 $@ }
+ prog $@
+
+ +

+will work, but will pollute prog's environment with a set of +positional parameters that have no meaning to it. A better script is: +

+ +
+ #!/command/execlineb
+ elgetpositionals
+ foreground { echo $0 $@ }
+ emptyenv -P
+ prog $@
+
+ +

+which will run prog with the same environment as the script's +caller. +

+ + + +

Substituting positional parameters without touching the environment

+ +

+ Most of the time, you just need to substitute the positional parameters +in your execline script, and don't need to go through the whole +elgetpositionals and +emptyenv chain. execline comes with an +integrated substitution mechanism, that does not touch the environment +at all: the -S n option. +

+ +

+ Scripts beginning with: +

+ +
+#!/command/execlineb -Sn
+foobar...
+
+ +

+ are equivalent to: +

+ +
+#!/command/execlineb
+elgetpositionals -Pn
+emptyenv -P
+foobar...
+
+ +

+ So, to summarize, from most efficient (but less flexible) to least efficient +(but more flexible): +

+ + + + + diff --git a/doc/el_semicolon.html b/doc/el_semicolon.html new file mode 100644 index 0000000..615b411 --- /dev/null +++ b/doc/el_semicolon.html @@ -0,0 +1,124 @@ + + + + +execline: block management + + + + + + +

+execline
+Software
+skarnet.org +

+ +

Blocks

+ +

+A command line (and thus an execline script) is one-dimensional. But a +Unix execution flow can be two-dimensional: when two +instructions are sequenced, for instance. In that case, we need a +way to extract two command lines from one argv. +That is precisely what blocks are made for. +

+ +

+ execline commands that need more than one linear set of arguments +use blocks. For instance, the +foreground command needs to spawn a +first process, then execute into a second one. It reads the command +line for the first process from a block, and the command line for the +second process from the rest of the argv. In the following script: +

+
+ #!/command/execlineb
+ foreground { echo 1 } echo 2
+
+

+ echo 1 is read from a block and spawned; then +echo 2 is executed. +

+ +

execlineb syntax

+ +

+ In execlineb scripts, blocks are +delimited by braces. They can be nested. +

+ +

argv syntax

+ +

+ execlineb reads and parses the script, and converts it into an argv +(a simple Unix command line) with a different syntax for blocks. +In an argv, blocks are not delimited by braces; +they are made of quoted arguments and terminated by an +empty word (""). A quoted argument begins with a space. + Nested blocks are represented by arguments being +quoted several times, i.e. having several spaces in front of them; +an empty word inside a block +gets quoted too, i.e. it will be represented as a series of +spaces. +

+ +

+ Actually, the block-reading commands know nothing about braces; +they only understand the "quoted arguments + empty word" syntax. +So if you want to use foreground +from your shell to sequence echo 1 and +echo 2, you will have to write +

+ +
+ $ foreground ' echo' ' 1' '' echo 2
+
+ +

+ You do not really need to quote every argument inside a block in +that simple case. The following command works as well: +

+ +
+ $ foreground echo 1 '' echo 2
+
+ +

+ However, this is bad practice, because it leads to a security hole: +commands that perform +substitution inside a block may +produce empty words, which may modify your script's execution flow. +

+ +
+ $ define FOO '' foreground ' echo' ' ${FOO}' ' rm' ' -rf' ' /' '' echo blah
+
+ +

+ is safe, whereas +

+ +
+ $ define FOO '' foreground echo '${FOO}' rm -rf / '' echo blah
+
+ +

+ has very much unwanted results. (Don't try this at home.) +

+ +

+ You can use the EXECLINE_STRICT environment variable to +check proper block quoting. If that variable contains 1, +commands that read blocks will print a warning message everytime +they find an unquoted argument inside a block. If that variable +contains 2 or a bigger integer, commands will print an +error message and die on unquoted arguments. +
You can use execlineb's +-w or -W +switch to set EXECLINE_STRICT to 1 or 2. +

+ + + diff --git a/doc/el_substitute.html b/doc/el_substitute.html new file mode 100644 index 0000000..4da03f5 --- /dev/null +++ b/doc/el_substitute.html @@ -0,0 +1,309 @@ + + + + + execline: variable substitution + + + + + + +

+execline
+Software
+skarnet.org +

+ +

Variable substitution

+ +

+ In a shell, when you write +

+
+ $ A='foobar' ; echo $A
+
+

+ the echo command is given the argument foobar. +The foobar value has been substituted for the +A variable. +

+

+ Although execline maintains no state, and thus has no +real variables, it provides such a substitution facility +via substitution commands, namely: +

+ + +

+ A substitution command takes a key, i.e. a string +(which can contain any character but $, { and +}, although it is recommended to use only alphanumerical +characters), and a way to compute a value. +

+ +

Basics

+ + + +

+The simplest example is the following: +

+ +
+#!/command/execlineb
+define FOO blah
+echo $FOO
+
+ +

+ which will replace the FOO key with the blah value, +then execute the echo command. So that script will print +blah on stdout. +

+ + +

Quoting

+ +

+ execline allows you to write literal ${foo} constructs +even when the foo variable is being substituted, thanks to a +quoting mechanism. + Brace (pun intended) yourself: the following is the most complex part +of the whole language. +

+ +

Rationale

+ +

+ If we want to be able to have a literal ${foo}, then: +

+ + +

Syntax

+ +

+ Rule: +

+ + + +

+ And now, the catch: the execlineb launcher, +as well as the shell, +interprets backslashes as escape characters. To make a word that contains +a backlash, you need to write two backslashes in your execline +script or shell command line. That means that the whole number of backslashes +you must write before your ${foo} sequence must be doubled +for the substitution command to read the proper number of backslashes and +perform its work correctly.
+ Once you keep that in mind, the quoting rule is logical. +

+ +

Example

+ +

+ The quoting rule is best illustrated with the following example, where +the A key is substituted, and the $B sequences mean +nothing special. +

+ +
+#!/command/execlineb
+define A val
+foreground { echo $A \\$A \\\\$A \\\\\\$A \\\\\\\\$A \\\\\\\\\\$A }
+             echo $B \\$B \\\\$B \\\\\\$B \\\\\\\\$B \\\\\\\\\\$B
+
+

+ prints +

+
+val $A \val \$A \\val \\$A
+$B \$B \\$B \\\$B \\\\$B \\\\\$B
+
+ +

+ Phew. +

+ + +

Value transformations

+
+ +

+ A value can go through +several transformations before it is +substituted. It can be crunched, +chomped, and/or +split. +

+ + +

Substitution of split values

+
+ +

+ A split value for FOO means that +a word containing ${FOO} will be replaced by zero, one, or +(usually) more than one word. The value actually means a +list of values. +

+ +

+ The rule is: substituting a list of values +(v1, v2, ...) for a key A is the +same as listing the substitutions of every value vi +for A.
+ For instance, +

+ +
+#!/command/execlineb
+define -s FOO "v1 v2 v3" echo prefix-${FOO}-postfix
+
+ +

+ will substitute three values for $FOO: v1, v2 +and v3. So the echo command will be called with three +arguments: prefix-v1-postfix, prefix-v2-postfix, and +prefix-v3-postfix. +

+ +

+(Implementation note: the fact that word prefixes are kept is +what makes execline's subtitutions secure. +Blocks are implemented via prefix +space characters; a substitution occurring inside a block will always produce +words beginning with the right amount of spaces, thus substituted +values cannot prematurely terminate a block.) +

+ + +

Recursive substitutions

+ +

+ A direct consequence of that rule is that substitutions will be performed +recursively if more than one key appears in one word and the values for +those keys are split. Parallel substitutions are performed from left to +right. For instance, in +

+ +
+#!/command/execlineb
+define -s B "1 2 3" echo ${B}x${B}
+
+

+ the ${B}x${B} word will be replaced with nine words: +1x1, 1x2, 1x3, 2x1, 2x2, +2x3, 3x1, 3x2, and 3x3, in that order. +
Here is an example with two distinct substitutions in parallel: +

+ +
+#!/command/execlineb
+multisubstitute
+{
+  define -s A "a b c d"
+  define -s B "1 2 3"
+}
+echo ${A}x${B}
+
+ +

+ The ${A}x${B} word will be replaced with twelve words: +ax1, ax2, ax3, bx1, bx2, +bx3, cx1, cx2, cx3, dx1, +dx2, and dx3, in that order. You can check that the +order of the define directives in +multisubstitute does not matter. +

+ +

+If the left-to-right order does not suit you, then you should perform +serial substitutions. For instance, the previous script can +be replaced with +

+ +
+#!/command/execlineb
+define -s B "1 2 3"
+define -s A "a b c d"
+echo ${A}x${B}
+
+

+ and will substitute ${B} first, then ${A}. So it +will print +

+ +
+ax1 bx1 cx1 dx1 ax2 bx2 cx2 dx2 ax3 bx3 cx3 dx3
+
+ +

+ in that order. +

+ + +

Not for the faint of heart

+ +

+ If you think you have mastered the art of execline substitution, then +you can try to do better than these people: +

+ + + + + diff --git a/doc/el_transform.html b/doc/el_transform.html new file mode 100644 index 0000000..094533a --- /dev/null +++ b/doc/el_transform.html @@ -0,0 +1,204 @@ + + + + + execline: value transformation + + + + + + +

+execline
+Software
+skarnet.org +

+ +

Value transformation

+ +

+ You can apply 3 kinds of transformations to a value which is to be +substituted for a variable: +crunching, chomping and splitting. They +always occur in that order. +

+ + + +

Delimiters

+
+ +

+ The transformations work around delimiters. Delimiters are +the semantic bounds of the "words" in your value. + You can use any character (except the null character, which you cannot +use in execline scripts) as a delimiter, by giving a string consisting +of all the delimiters you want as the argument to the -d option +used by substitution commands. By default, the string " \n\r\t" +is used, which means that the default delimiters are spaces, newlines, +carriage returns and tabs. +

+ + + +

Crunching

+
+ +

+ You can tell the substitution command to merge sets of consecutive +delimiters into a single delimiter. For instance, to replace +three consecutive spaces, or a space and 4 tab characters, with a +single space. This is called crunching, and it is done +by giving the -C switch to the substitution command. The +remaining delimiter will always be the first in the sequence. +

+ +

+ Crunching is mainly useful when also splitting. +

+ + +

Chomping

+
+ +

+ Sometimes you don't want the last delimiter in a value. + Chomping deletes the last character of a value if it is a +delimiter. It can be requested by giving the -n switch to the +substitution command. Note that chomping always happens after +crunching, which means you can use crunching+chomping to ignore, for +instance, a set of trailing spaces. +

+ + + +

Splitting

+
+ +

+ In a shell, when you write +

+ +
+ $ A='foo bar' ; echo $A
+
+ +

+ the echo command is given two arguments, foo +and bar. The $A value has been split, +and the space between foo and bar acted as a +delimiter. +

+ +

+If you want to avoid splitting, you must write something like +

+ +
+ $ A='foo bar' ; echo "$A"
+
+ +

+ The doublequotes "protect" the spaces. Unfortunately, it's easy +to forget them and perform unwanted splits during script execution +- countless bugs happen because of the shell's splitting behaviour. +

+ +

+ execline provides a splitting facility, with +several advantages over the shell's: +

+ + + +

How it works

+ + + + + +

Decoding netstrings

+
+ +

+ Netstrings are +a way to reliably encode strings containing arbitrary characters. +execline takes advantage of this to offer a completely safe +splitting mechanism. If a substitution command is given an empty +delimiter string (by use of the -d "" option), the +splitting function will try to interpret the value as a sequence +of netstrings, every netstring representing a word. For instance, +in the following command line: +

+ +
+ $ define -s -d "" A '1:a,2:bb,0:,7:xyz 123,1: ,' echo '$A'
+
+ +

+ the echo command will be given five arguments: +

+ + + +

+ However, if the value is not a valid sequence of netstrings, the +substitution command will die with an error message. +

+ +

+ The dollarat command, for instance, +can produce a sequence of netstrings (encoding all the arguments +given to an execline script), meant to be decoded by a substitution +command with the -d "" option. +

+ + + diff --git a/doc/elgetopt.html b/doc/elgetopt.html new file mode 100644 index 0000000..a5650f2 --- /dev/null +++ b/doc/elgetopt.html @@ -0,0 +1,60 @@ + + + + + execline: the elgetopt command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The elgetopt program

+ +

+elgetopt performs getopt-style parsing on the +arguments to an execline script. +

+ +

Interface

+ +
+     elgetopt optstring prog...
+
+ + + +

Notes

+ + + + + diff --git a/doc/elgetpositionals.html b/doc/elgetpositionals.html new file mode 100644 index 0000000..d193413 --- /dev/null +++ b/doc/elgetpositionals.html @@ -0,0 +1,94 @@ + + + + + execline: the elgetpositionals command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The elgetpositionals program

+ +

+elgetpositionals substitutes the positional parameters of an execline script. +

+ +

Interface

+ +
+     elgetpositionals [ -P sharp ] prog...
+
+ + + +

Options

+ + + +

Notes

+ + + + + diff --git a/doc/elglob.html b/doc/elglob.html new file mode 100644 index 0000000..5b5d6aa --- /dev/null +++ b/doc/elglob.html @@ -0,0 +1,68 @@ + + + + + execline: the elglob command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The elglob program

+ +

+elglob performs globbing on a pattern, then executes +another program. +

+ +

Interface

+ +
+     elglob [ -v ] [ -w ] [ -s ] [ -m ] [ -e ] [ -0 ] variable pattern prog...
+
+ + + +

Options

+ + + + + diff --git a/doc/emptyenv.html b/doc/emptyenv.html new file mode 100644 index 0000000..81cf45a --- /dev/null +++ b/doc/emptyenv.html @@ -0,0 +1,57 @@ + + + + + execline: the emptyenv program + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The emptyenv program

+ +

+emptyenv empties the current environment, or cleans it up; then +executes a program. +

+ +

Interface

+ +
+     emptyenv [ -p ] prog...
+     emptyenv -c prog...
+     emptyenv [ -o ] [ -P ] prog...
+
+ +

+By default, emptyenv unsets all environment variables, then +execs into prog with its arguments. Options control which +environment variables are unset. +

+ +

Options

+ + + + + diff --git a/doc/exec.html b/doc/exec.html new file mode 100644 index 0000000..8655541 --- /dev/null +++ b/doc/exec.html @@ -0,0 +1,50 @@ + + + + + execline: the exec program + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The exec program

+ +

+exec executes the command line it is given. +

+ +

Interface

+ +
+     exec [ -c ] [ -l ] [ -a argv0 ]prog...
+
+ +

+exec execs into prog.... It does nothing else. +
Without options, exec can be seen as the execline NOP. +

+ +

Options

+ + + +

+The exec command, along with its options, is designed to emulate +the standard exec shell builtin, which replaces the shell with the +command it is given. +

+ + + diff --git a/doc/execline-shell.html b/doc/execline-shell.html new file mode 100644 index 0000000..b3526f0 --- /dev/null +++ b/doc/execline-shell.html @@ -0,0 +1,53 @@ + + + + + execline: the execline-shell script + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The execline-shell script

+ +

+execline-shell executes $HOME/.execline-shell +with the arguments it is given. +

+ +

Interface

+ +
+     /etc/execline-shell
+
+ + + +

Notes

+ + + + + diff --git a/doc/execline-startup.html b/doc/execline-startup.html new file mode 100644 index 0000000..5df401d --- /dev/null +++ b/doc/execline-startup.html @@ -0,0 +1,59 @@ + + + + + execline: the execline-startup script + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The execline-startup script

+ +

+execline-startup performs some system-specific +login initialization, then executes ${HOME}/.execline-loginshell. +

+ +

Interface

+ +
+     /etc/execline-startup
+
+ + + +

Notes

+ + + + + diff --git a/doc/execlineb.html b/doc/execlineb.html new file mode 100644 index 0000000..64f29bd --- /dev/null +++ b/doc/execlineb.html @@ -0,0 +1,246 @@ + + + + + execline: the execlineb command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The execlineb program

+ +

+execlineb reads and executes a script. +

+ +

Interface

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

+or +

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

+or in an executable file: +

+ +
+#!/command/execlineb [ -qwWpPSnmin ]
+script
+
+ +

+ Parsing phase. +

+ + + +

+ Environment management phase. +

+ + + +

+ Execution phase. +

+ + + +

Options

+ + + +

+ 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: +

+ + + +

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

+ +

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

+ + + +

+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. +

+ +

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. +

+ + + +

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 option, each execlineb +invocation uses up some space in the environment. +

+ + + diff --git a/doc/exit.html b/doc/exit.html new file mode 100644 index 0000000..1e94ebd --- /dev/null +++ b/doc/exit.html @@ -0,0 +1,44 @@ + + + + + execline: the exit program + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The exit program

+ +

+exit exits with a given exit code. +

+ +

Interface

+ +
+     exit [ n ]
+
+ +

+exit exits with the exit code n, or 0 if n is not +given (in which case it's the same as true). If n is not +a number, exit exits 100. +

+ + +

Notes

+ +

+exit is a standard shell builtin, with the same function. +

+ + + diff --git a/doc/export.html b/doc/export.html new file mode 100644 index 0000000..35a7f68 --- /dev/null +++ b/doc/export.html @@ -0,0 +1,43 @@ + + + + + execline: the export program + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The export program

+ +

+export sets an environment variable to a given value, then +executes a program. +

+ +

Interface

+ +
+     export var value prog...
+
+ +

+export sets the var environment variable to +the string value, then execs into prog with +its arguments. +

+ + + + + diff --git a/doc/fdblock.html b/doc/fdblock.html new file mode 100644 index 0000000..5b2bfa8 --- /dev/null +++ b/doc/fdblock.html @@ -0,0 +1,55 @@ + + + + + execline: the fdblock program + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The fdblock program

+ +

+fdblock sets or unsets the O_NONBLOCK flag on a given file descriptor +(which makes reading or writing non-blocking or blocking), then executes +a program. +

+ +

Interface

+ +
+     fdblock [ -n ] fd prog...
+
+ +

+fdblock makes the file descriptor number fd blocking, +no matter what its previous state was. It then execs into prog +with its arguments. +

+ +

Options

+ + + +

Notes

+ + + + + diff --git a/doc/fdclose.html b/doc/fdclose.html new file mode 100644 index 0000000..15265ac --- /dev/null +++ b/doc/fdclose.html @@ -0,0 +1,44 @@ + + + + + execline: the fdclose program + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The fdclose program

+ +

+fdclose closes a given file descriptor, then +executes a program. +

+ +

Interface

+ +
+     fdclose fd prog...
+
+ +

+fdclose closes the file descriptor number fd, then +execs into prog with its arguments. +

+ +

Notes

+ + + + + diff --git a/doc/fdmove.html b/doc/fdmove.html new file mode 100644 index 0000000..8498408 --- /dev/null +++ b/doc/fdmove.html @@ -0,0 +1,55 @@ + + + + + execline: the fdmove program + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The fdmove program

+ +

+fdmove moves or copies a given file descriptor, then +executes a program. +

+ +

Interface

+ +
+     fdmove [ -c ] fdto fdfrom prog...
+
+ +

+fdmove moves the file descriptor number fdfrom, +to number fdto, then execs into prog with its arguments. +If fdto is open, fdmove closes it before moving +fdfrom to it. +

+ +

Options

+ + + +

Notes

+ + + + + diff --git a/doc/fdreserve.html b/doc/fdreserve.html new file mode 100644 index 0000000..ef047dc --- /dev/null +++ b/doc/fdreserve.html @@ -0,0 +1,92 @@ + + + + + execline: the fdreserve program + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The fdreserve program

+ +

+fdreserve updates the environment with file descriptors that +are guaranteed safe to use, then executes a program. +

+ +

Interface

+ +
+     fdreserve n prog...
+
+ + + +

Common use

+ +

+fdreserve can be used when you do not want to hardcode file +descriptors in your scripts. For instance, to create a pipe, you could +use: +

+ +
+ #!/command/execlineb
+ fdreserve 2
+ multisubstitute
+ {
+   importas fdr FD0
+   importas fdw FD1
+  }
+ piperw $fdr $fdw
+ prog...
+
+ +

+ Warning: fdreserve does not allocate descriptors, it merely returns +descriptors that are free at the time it is run. A program like +

+ +
+ #!/command/execlineb
+ fdreserve 3
+ multisubstitute
+ {
+   importas fdr FD0
+   importas fdw FD1
+ }
+ piperw $fdr $fdw
+ fdreserve 1
+ multisubstitute
+ {
+   importas oldfd FD2
+   importas newfd FD0
+ }
+ prog...
+
+ +

+may fail, because oldfd and newfd may be the same. +To avoid that, you should make sure that all descriptors returned by +fdreserve are actually allocated before calling fdreserve +again. +(Thanks to Paul Jarc for having +spotted that case.) +

+ + + diff --git a/doc/forbacktickx.html b/doc/forbacktickx.html new file mode 100644 index 0000000..9e09c81 --- /dev/null +++ b/doc/forbacktickx.html @@ -0,0 +1,77 @@ + + + + + execline: the forbacktickx command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The forbacktickx program

+ +

+forbacktickx runs a program and uses its output as loop elements to +run another program. +

+ +

Interface

+ +

+ In an execlineb script: +

+ +
+     forbacktickx [ -p | -x breakcode ] [ -n ] [ -C | -c ] [ -0 | -d delim ] variable { gen... } loop...
+
+ + + +

Options

+ + + +

Notes

+ + + + + diff --git a/doc/foreground.html b/doc/foreground.html new file mode 100644 index 0000000..a2a465f --- /dev/null +++ b/doc/foreground.html @@ -0,0 +1,57 @@ + + + + + execline: the foreground command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The foreground program

+ +

+foreground executes a sequence of commands. +

+ +

Interface

+ +

+ In an execlineb script: +

+ +
+     foreground { prog1... } prog2...
+
+ + + +

Notes

+ + + + + diff --git a/doc/forx.html b/doc/forx.html new file mode 100644 index 0000000..86729b8 --- /dev/null +++ b/doc/forx.html @@ -0,0 +1,66 @@ + + + + + execline: the forx command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The forx program

+ +

+forx runs a loop. +

+ +

Interface

+ +

+ In an execlineb script: +

+ +
+     forx [ -p | -x breakcodes ] variable { args... } loop...
+
+ + + +

Options

+ + + +

Notes

+ + + + + diff --git a/doc/getpid.html b/doc/getpid.html new file mode 100644 index 0000000..fb60c7c --- /dev/null +++ b/doc/getpid.html @@ -0,0 +1,44 @@ + + + + + execline: the getpid program + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The getpid program

+ +

+getpid stores its process ID in a given environment variable, +then executes a program. +

+ +

Interface

+ +
+     getpid var prog...
+
+ +

+getpid stores its PID in the var variable, then +execs into prog with its arguments. +

+ +

Notes

+ + + + + diff --git a/doc/grammar.html b/doc/grammar.html new file mode 100644 index 0000000..6c26dbd --- /dev/null +++ b/doc/grammar.html @@ -0,0 +1,160 @@ + + + + + execline: language design and grammar + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The execline language design and grammar

+ + +

execline principles

+ +

+ Here are some basic Unix facts: +

+ +
+ +

+ Knowing that, and wanting lightweight and efficient scripts, I +wondered: "Why should the interpreter stay in memory while the script +is executing ? Why not parse the script once and for all, put +it all into one argv, and just execute into that argv, +relying on external commands (which will be called from within the +script) to control the execution flow ?" +

+ +

execline was born.

+ + + + +

Grammar of an execline script

+ +

+An execline script can be parsed as follows: +

+ +
+ <instruction> = <> | external options <arglist> <instruction> | builtin options <arglist> <blocklist> <instruction>
+ <arglist> = <> | arg <arglist>
+ <blocklist> = <> | <block> <blocklist>
+ <block> = { <arglist> } | { <instrlist> }
+ <instrlist> = <> | <instruction> <instrlist>
+
+ +

+(This grammar is ambivalent, but much simpler to understand than the +non-ambivalent ones.) +

+ +
+ + +

execline features

+ +

+ execline commands can perform some transformations on +their argv, to emulate some aspects of a shell. Here are +descriptions of these features: +

+ + + + + diff --git a/doc/heredoc.html b/doc/heredoc.html new file mode 100644 index 0000000..f49f880 --- /dev/null +++ b/doc/heredoc.html @@ -0,0 +1,56 @@ + + + + + execline: the heredoc program + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The heredoc program

+ +

+heredoc runs a command with a certain string fed to a +file descriptor. +

+ +

Interface

+ +
+     heredoc [ -d ] fd string prog...
+
+ + + +

Options

+ + + +

Notes

+ + + + + diff --git a/doc/homeof.html b/doc/homeof.html new file mode 100644 index 0000000..31f2a40 --- /dev/null +++ b/doc/homeof.html @@ -0,0 +1,37 @@ + + + + + execline: the homeof program + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The homeof program

+ +

+homeof prints the home directory of a user. +

+ +

Interface

+ +
+     homeof user
+
+ +

+homeof finds the name of user's home directory, writes +it on stdout, then exits 0. If an error occurs, it prints nothing on +stdout but exits 111 with an explanatory message on stderr. +

+ + + diff --git a/doc/if.html b/doc/if.html new file mode 100644 index 0000000..2157a07 --- /dev/null +++ b/doc/if.html @@ -0,0 +1,68 @@ + + + + + execline: the if command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The if program

+ +

+if performs conditional execution. +

+ +

Interface

+ +

+ In an execlineb script: +

+ +
+     if [ -X ] [ -n ] [ -t | -x exitcode ] { prog1... } prog2...
+
+ + + +

Options

+ + + +

Notes

+ + + + + diff --git a/doc/ifelse.html b/doc/ifelse.html new file mode 100644 index 0000000..2298cf8 --- /dev/null +++ b/doc/ifelse.html @@ -0,0 +1,59 @@ + + + + + execline: the ifelse command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The ifelse program

+ +

+ ifelse performs conditional execution, with two branches. +

+ +

Interface

+ +

+ In an execlineb script: +

+
+     ifelse [ -X ] [ -n ] { prog1... } { prog2... } prog3...
+
+ + + +

Options

+ + + +

Notes

+ + + + + diff --git a/doc/ifte.html b/doc/ifte.html new file mode 100644 index 0000000..40b0ec9 --- /dev/null +++ b/doc/ifte.html @@ -0,0 +1,67 @@ + + + + + execline: the ifte command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The ifte program

+ +

+ifte performs a conditional alternative. +

+ +

Interface

+ +

+ In an execlineb script: +

+ +
+     ifte [ -X ] [ -n ] { progthen... } { progelse... } progif...
+
+ + + +

Options

+ + + +

Notes

+ +

+ ifte is a simpler version of ifthenelse. +It performs only conditional execution, not instruction sequence. +

+ +

+"ifthenelse { progif } { progthen } { progelse } remainder" is the +equivalent of "foreground { ifte { progthen } { progelse } progif } remainder". +

+ + + diff --git a/doc/ifthenelse.html b/doc/ifthenelse.html new file mode 100644 index 0000000..3180412 --- /dev/null +++ b/doc/ifthenelse.html @@ -0,0 +1,59 @@ + + + + + execline: the ifthenelse command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The ifthenelse program

+ +

+ifthenelse performs a conditional alternative. +

+ +

Interface

+ +

+ In an execlineb script: +

+ +
+     ifthenelse [ -X ] [ -s ] { progif... } { progthen... } { progelse... } prog...
+
+ + + +

Options

+ + + + + diff --git a/doc/import.html b/doc/import.html new file mode 100644 index 0000000..1c6896c --- /dev/null +++ b/doc/import.html @@ -0,0 +1,37 @@ + + + + + execline: the import program + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The import program

+ +

+import replaces an environment variable name with its value, +then executes another program. +

+ +

Interface

+ +
+     import [ -i | -D default ] [ -s ] [ -C | -c ] [ -n ] [ -d delim ] envvar prog...
+
+ + + + + diff --git a/doc/importas.html b/doc/importas.html new file mode 100644 index 0000000..a9c6f15 --- /dev/null +++ b/doc/importas.html @@ -0,0 +1,57 @@ + + + + + execline: the importas program + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The importas program

+ +

+importas replaces a literal with the value of an +environment variable, then executes another program. +

+ +

Interface

+ +
+     importas [ -i | -D default ] [ -s ] [ -C | -c ] [ -n ] [ -d delim ] variable envvar prog...
+
+ + + +

Options

+ + + + + diff --git a/doc/index.html b/doc/index.html new file mode 100644 index 0000000..682e935 --- /dev/null +++ b/doc/index.html @@ -0,0 +1,213 @@ + + + + + execline: a small scripting language + + + + + + +

+Software
+skarnet.org +

+ +

execline

+ +

What is it ?

+ +

+ execline is a (non-interactive) scripting language, like sh ; +but its syntax is quite different from a traditional shell syntax. +The execlineb program is meant to be used as an interpreter for a +text file; the other commands are essentially useful inside an +execlineb script. +

+ +

+ execline is as powerful as a shell: it features +conditional loops, +getopt-style option handling, +filename globbing, and more. + Meanwhile, its syntax is far more logic and predictable than the +shell's syntax, and has no security issues. +

+ + + +
+ +

Installation

+ +

Requirements

+ + + +

Licensing

+ +

+ execline is free software. It is available under the +ISC license. +

+ +

Download

+ + + +

Compilation

+ + + +

Upgrade notes

+ + + +
+ +

Special note

+ +

+ Before version 2.0.0.0, execline used the slashpackage convention by default. + This is not the case anymore; nevertheless, the examples in this documentation +still use #!/command/execlineb as their shebang line, and assume that +the execline binaries are available in /command. Adapt them according +to your installation: the shebang lines for your system might be something like +#!/bin/execlineb, or #!/usr/bin/execlineb, or +#!/usr/local/bin/execlineb, or something else entirely. +

+ +
+ +

Reference

+

Commands

+ +

+ All these commands exit 111 if they encounter a temporary error, and +100 if they encounter a permanent error - such as a misuse. +

+

+ (Script parser / launcher) +

+ +

+ (Process state control) +

+ +

+ (Basic block management) +

+ +

+ (Variable management) +

+ +

+ (Loops) +

+ +

+ (Positional parameters and options management) +

+ +

+ (Miscellaneous) +

+ + +

Provided scripts: example .profile replacement

+ + + +

Fun stuff

+ + + +

Related resources

+ + + + + diff --git a/doc/loopwhilex.html b/doc/loopwhilex.html new file mode 100644 index 0000000..9def60f --- /dev/null +++ b/doc/loopwhilex.html @@ -0,0 +1,60 @@ + + + + + execline: the loopwhilex command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The loopwhilex program

+ +

+loopwhilex performs a conditional loop. +

+ +

Interface

+ +
+     loopwhilex [ -n ] [ -x exitcodes ] prog...
+
+ + + +

Options

+ + + +

Notes

+ + + + + diff --git a/doc/multidefine.html b/doc/multidefine.html new file mode 100644 index 0000000..03f6b22 --- /dev/null +++ b/doc/multidefine.html @@ -0,0 +1,69 @@ + + + + + execline: the multidefine command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The multidefine program

+ +

+multidefine splits a value and defines several variables at once, +then executes another program. +

+ +

Interface

+ +

+ In an execlineb script: +

+ +
+     multidefine [ -0 ] [ -r ] [ -C | -c ] [ -n ] [ -d delim ] value { variables... } prog...
+
+ + + +

Options

+ + + + + diff --git a/doc/multisubstitute.html b/doc/multisubstitute.html new file mode 100644 index 0000000..6400187 --- /dev/null +++ b/doc/multisubstitute.html @@ -0,0 +1,121 @@ + + + + + execline: the multisubstitute command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The multisubstitute program

+ +

+multisubstitute performs several substitutions at once in +its argv, then executes another program. +

+ +

Interface

+ +

+ In an execlineb script: +

+ +
+     multisubstitute
+     {
+       [ define [ -n ] [ -s ] [ -C | -c ] [ -d delim ] variable value ]
+       [ importas [ -i | -D default ] [ -n ] [ -s ] [ -C | -c ] [ -d delim ] variable envvar ]
+       [ import [ -i | -D default ] [ -n ] [ -s ] [ -C | -c ] [ -d delim ] envvar ]
+       [ elglob [ -v ] [ -w ] [ -s ] [ -m ] [ -e ] [ -0 ] variable pattern ]
+       [ elgetpositionals [ -P sharp ] ]
+       [ multidefine value { variable... } ]
+       ...
+     }
+     prog...
+
+ + + +

Options

+ + + +

Rationale

+ +

Security

+ +

+ multisubstitute can be used to avoid unwanted +serial substitutions. Consider the following script: +

+ +
+ #!/command/execlineb
+ export A wrong
+ define B ${A}
+ import A
+ echo ${B}
+
+ +

+ Running it will print wrong, because A is substituted +after B. On the contrary, the following script: +

+ +
+ #!/command/execlineb
+ export A wrong
+ multisubstitute
+ {
+   define B ${A}
+   import A
+ }
+ echo ${B}
+
+ +

+ will print ${A}, because A and B are substituted at the same +time. Serial substitution may be what you want - but when in doubt, +always perform parallel substitution. +

+ +

Efficiency

+ +

+Substitution is a costly mechanism: +the whole argv is read three times and rewritten twice. +Serial substitution multiplies the cost by the number of +substitutions, whereas parallel substitution pays the price only once. +

+ +

Credits

+ +

+Paul Jarc first originated the +idea of the multisubstitute command and a possible syntax. +

+ + + diff --git a/doc/pipeline.html b/doc/pipeline.html new file mode 100644 index 0000000..4f6677f --- /dev/null +++ b/doc/pipeline.html @@ -0,0 +1,67 @@ + + + + + execline: the pipeline command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The pipeline program

+ +

+pipeline runs two commands with a pipe between them. +

+ +

Interface

+ +

+ In an execlineb script: +

+ +
+     pipeline [ -d ] [ -r | -w ] { prog1... } prog2...
+
+ + + +

Options

+ + + +

Notes

+ + + + + diff --git a/doc/piperw.html b/doc/piperw.html new file mode 100644 index 0000000..64b9477 --- /dev/null +++ b/doc/piperw.html @@ -0,0 +1,38 @@ + + + + + execline: the piperw command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The piperw program

+ +

+piperw creates a pipe (an anonymous one), then +executes a program. +

+ +

Interface

+ +
+     piperw fdr fdw prog...
+
+ +

+piperw creates a pipe with descriptor fdw as the +writing end and descriptor fdr as the reading end. +It then execs into prog with its arguments. +

+ + + diff --git a/doc/quine-dam.txt b/doc/quine-dam.txt new file mode 100644 index 0000000..c69a52c --- /dev/null +++ b/doc/quine-dam.txt @@ -0,0 +1,110 @@ +#! /command/execlineb -P +# Public Domain. +# See comments below. +# (Search for "HERE".) +# +define -sCd "\n" lns " +${p} ${bubble} is the end of the quine's data. +${p} They represent the following code, with various quotations: +${p} ${b} (backslash) is represented as ${d}${ob}b${cb} +${p} ${q} (double quote) is represented as ${d}${ob}q${cb} +${p} ${p} (sharp/pound/shibboleth/whatever) is represented as ${d}${ob}p${cb} +${p} ${ob} (open brace) is represented as ${d}${ob}ob${cb} +${p} ${cb} (closed brace) is represented as ${d}${ob}cb${cb} +${p} ${d} (dollar) is represented as ${d}${ob}d${cb} +${p} ${bubble} (the magic word) is represented as ${d}${ob}bubble${cb} +${p} (The point of the magic word is to allow the reader +${p} to conveniently skip over the large data section.) +${p} +${p} Now we have the quine's code! +${p} +${p} First, print the lines that come before the data. +foreground ${ob} printf %s ${b}${p}${b}!${q} ${q} ${cb} +foreground ${ob} printf %s${b}${b}n ${q}/command/execlineb -P${q} ${cb} +foreground ${ob} printf %s${b}${b}n ${b}${p}${q} Public Domain.${q} ${cb} +foreground ${ob} printf %s${b}${b}n ${b}${p}${q} See comments below.${q} ${cb} +foreground ${ob} printf %s ${b}${p}${q} (Search for ${q} ${cb} +foreground ${ob} printf %s${b}${b}n ${b}${q}${bubble}${b}${q}.) ${cb} +foreground ${ob} printf %s${b}${b}n ${b}${p} ${cb} +foreground ${ob} printf %s ${q}define -sCd ${b}${q}${b}${b}n${b}${q} lns ${b}${q}${q} ${cb} +${p} Next, print the data themselves, as data. +for lin ${ob} ${d}${ob}lns${cb} ${cb} ${ob} +multisubstitute ${ob} +define b ${d}${ob}b${cb} +define q ${d}${ob}q${cb} +define p ${d}${ob}p${cb} +define ob ${d}${ob}ob${cb} +define cb ${d}${ob}cb${cb} +define d ${d}${ob}d${cb} +define bubble ${d}${ob}bubble${cb} +define intron ${d}${ob}intron${cb} +${cb} printf ${b}${b}n%s ${d}${ob}lin${cb} ${cb} +foreground ${ob} printf %s${b}${b}n ${b}${q} ${cb} +${p} Finally, use the data to print the code! +for lin ${ob} ${d}${ob}lns${cb} ${cb} ${ob} +multisubstitute ${ob} +define b ${b}${b} +define q ${b}${q} +define p ${b}${p} +define ob ${b}${ob} +define cb ${b}${cb} +define d ${d} +define bubble ${bubble} +define intron ${q}${intron}${q} +${cb} printf %s${b}${b}n ${d}${ob}lin${cb} ${cb} +${p} That's all, folks! - Well, that wasn't so hard, was it? +${p} (This quine was written by - see +${p} +${p} for more information on quines and how to write them.)" +# HERE is the end of the quine's data. +# They represent the following code, with various quotations: +# \ (backslash) is represented as ${b} +# " (double quote) is represented as ${q} +# # (sharp/pound/shibboleth/whatever) is represented as ${p} +# { (open brace) is represented as ${ob} +# } (closed brace) is represented as ${cb} +# $ (dollar) is represented as ${d} +# HERE (the magic word) is represented as ${bubble} +# (The point of the magic word is to allow the reader +# to conveniently skip over the large data section.) +# +# Now we have the quine's code! +# +# First, print the lines that come before the data. +foreground { printf %s \#\!" " } +foreground { printf %s\\n "/command/execlineb -P" } +foreground { printf %s\\n \#" Public Domain." } +foreground { printf %s\\n \#" See comments below." } +foreground { printf %s \#" (Search for " } +foreground { printf %s\\n \"HERE\".) } +foreground { printf %s\\n \# } +foreground { printf %s "define -sCd \"\\n\" lns \"" } +# Next, print the data themselves, as data. +for lin { ${lns} } { +multisubstitute { +define b ${b} +define q ${q} +define p ${p} +define ob ${ob} +define cb ${cb} +define d ${d} +define bubble ${bubble} +define intron ${intron} +} printf \\n%s ${lin} } +foreground { printf %s\\n \" } +# Finally, use the data to print the code! +for lin { ${lns} } { +multisubstitute { +define b \\ +define q \" +define p \# +define ob \{ +define cb \} +define d $ +define bubble HERE +define intron "NOTICE HOW THIS SENTENCE APPEARS ONLY ONCE IN THIS QUINE?" +} printf %s\\n ${lin} } +# That's all, folks! - Well, that wasn't so hard, was it? +# (This quine was written by - see +# +# for more information on quines and how to write them.) diff --git a/doc/quine-jriou.txt b/doc/quine-jriou.txt new file mode 100644 index 0000000..f8e5455 --- /dev/null +++ b/doc/quine-jriou.txt @@ -0,0 +1,28 @@ +#!/command/execlineb +define A "#!/command/execlineb" +define B "fine G $ foreground { echo ${C} } +echo -n foreground ${D} define C ${E}${C}${R}foreground +${D} echo ${G}${D}A${H} ${H}${R}foreground +${D} echo define A ${G}${D}C${H}${G}${D}A${H}${G}${D}C${H} ${H}${R}echo +-n define B ${G}${D}C${H} ${H}${R}foreground +${D} echo -n ${G}${D}B${H} ${H}${R}foreground +${D} multisubstitute ${D} define C ${E}${C} define D ${E}${D}${R}define +E ${E}${E}${R}define +H ${E}${H} define R ${C}${R}${C} ${H} de } echo ${B}" +foreground { define C \" +foreground { echo ${A} } +foreground { echo define A ${C}${A}${C} } +echo -n define B ${C} } +foreground { echo -n ${B} } +foreground { multisubstitute { define C \" define D \{ +define E \\ +define H \} define R " +" } define G $ foreground { echo ${C} } +echo -n foreground ${D} define C ${E}${C}${R}foreground +${D} echo ${G}${D}A${H} ${H}${R}foreground +${D} echo define A ${G}${D}C${H}${G}${D}A${H}${G}${D}C${H} ${H}${R}echo +-n define B ${G}${D}C${H} ${H}${R}foreground +${D} echo -n ${G}${D}B${H} ${H}${R}foreground +${D} multisubstitute ${D} define C ${E}${C} define D ${E}${D}${R}define +E ${E}${E}${R}define +H ${E}${H} define R ${C}${R}${C} ${H} de } echo ${B} diff --git a/doc/quine-prj-2.txt b/doc/quine-prj-2.txt new file mode 100644 index 0000000..9c60b92 --- /dev/null +++ b/doc/quine-prj-2.txt @@ -0,0 +1,15 @@ +#!/command/execlineb +define e "#!/command/execlineb +define e ${q}${E}${q} +multisubstitute { +define q ${b}${q} +define b ${b}${b} +define E $e +} +echo $e" +multisubstitute { +define q \" +define b \\ +define E $e +} +echo $e diff --git a/doc/quine-prj-3.txt b/doc/quine-prj-3.txt new file mode 100644 index 0000000..e5b5708 --- /dev/null +++ b/doc/quine-prj-3.txt @@ -0,0 +1,13 @@ +#!/command/execlineb -P +define e "#!/command/execlineb -P +define e ${q}${E}${q} +export E $e +define q ${b}${q} +define b ${b}${b} +import E +echo $e" +export E $e +define q \" +define b \\ +import E +echo $e diff --git a/doc/quine-prj.txt b/doc/quine-prj.txt new file mode 100644 index 0000000..8d2643f --- /dev/null +++ b/doc/quine-prj.txt @@ -0,0 +1,13 @@ +#!/command/execlineb +define e "#!/command/execlineb +define e $q${E}${q} +env e=$e +define q ${b}${q} +define b ${b}${b} +importas E e +echo $e" +env e=$e +define q \" +define b \\ +importas E e +echo $e diff --git a/doc/redirfd.html b/doc/redirfd.html new file mode 100644 index 0000000..fd29ef4 --- /dev/null +++ b/doc/redirfd.html @@ -0,0 +1,100 @@ + + + + + execline: the redirfd command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The redirfd program

+ +

+redirfd redirects a given file descriptor to a file, then +executes a program. +

+ +

Interface

+ +
+     redirfd [ -r | -w | -u | -a | -c | -x ] [ -n | -b ] fd file prog...
+
+ +

+redirfd redirects the file descriptor number fd +to file, then execs into prog.... +

+ +

Options

+ +

+ One and only one of the -r, -w, -u, -a, -c, or -x options must be given; +the -n and -b options may be added in any case. +

+ +
    +
  • -r : open file for reading.
  • +
  • -w : open file for writing, truncating it if it already exists.
  • +
  • -u : open file for reading and writing.
  • +
  • -a : open file for appending, creating it if it doesn't exist.
  • +
  • -c : open file for appending. Do not create it if it doesn't exist.
  • +
  • -x : open file for writing, creating it, failing if it already exists.
  • +
  • -n : open file in non-blocking mode.
  • +
  • -b : change mode of file after opening it: +to non-blocking mode if the -n option was not given, +to blocking mode if it was.
  • +
+ +

Notes

+ +
+ +

Special fifo handling

+ +

+ The -n and -b options are especially useful with +named pipes. +

+ + + + + diff --git a/doc/runblock.html b/doc/runblock.html new file mode 100644 index 0000000..6f5386e --- /dev/null +++ b/doc/runblock.html @@ -0,0 +1,75 @@ + + + + + execline: the runblock program + + + + + + +

+execline
+Software
+www.skarnet.org +

+ +

The runblock program

+ +

+runblock's purpose is to help you write execline commands +in the execline language. It can only be used inside an execline +script. If the script has been given blocks as arguments, runblock +allows you to execute one of the blocks individually. +

+ +

Interface

+ +
+     runblock [ -P ] [ -n argshift ] [ -r ] n
+
+ + + +

Example: implementing the ifelse command

+ +

+ Suppose that we want to implement the ifelse command as +an execline script, using the ifte command. +runblock allows us to do it in a simple way: +

+ +
+ #!/command/execlineb
+ ifte { runblock 2 } { runblock -r 2 } runblock 1
+
+ +

+ That's it. +

+ +

Credits

+ +

+ The runblock idea, as well as the ifelse idea, comes +from Paul Jarc. +

+ + + diff --git a/doc/shift.html b/doc/shift.html new file mode 100644 index 0000000..775e472 --- /dev/null +++ b/doc/shift.html @@ -0,0 +1,68 @@ + + + + + execline: the shift program + + + + + + +

+execline
+Software
+www.skarnet.org +

+ +

The shift program

+ +

+shift shifts the positional parameters of an execline script. +

+ +

Interface

+ +
+     shift [ -n argn ] [ -b blockn ] prog...
+
+ + + +

Details

+ + + +

Notes

+ + + + + diff --git a/doc/tryexec.html b/doc/tryexec.html new file mode 100644 index 0000000..2fcc7b6 --- /dev/null +++ b/doc/tryexec.html @@ -0,0 +1,67 @@ + + + + + execline: the tryexec command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The tryexec program

+ +

+tryexec executes into a command line, with a fallback. +

+ +

Interface

+ +

+ In an execlineb script: +

+ +
+     tryexec [ -n ] [ -c ] [ -l ] [ -a argv0 ] { prog1... } prog2...
+
+ + + +

Options

+ + + +

+ The -c, -l and -a options have the same +semantics as with the exec program. +

+ +

Notes

+ + + + + diff --git a/doc/umask.html b/doc/umask.html new file mode 100644 index 0000000..5edf511 --- /dev/null +++ b/doc/umask.html @@ -0,0 +1,44 @@ + + + + + execline: the umask command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The umask program

+ +

+umask sets the umask (file creation mask), +then executes a program. +

+ +

Interface

+ +
+     umask mask prog...
+
+ +

+umask sets the current umask to mask, +then execs into prog.... +

+ +

Notes

+ +

+umask is a standard shell builtin. Be careful if you want to +use the umask command outside of an execline script. +

+ + + diff --git a/doc/unexport.html b/doc/unexport.html new file mode 100644 index 0000000..331189c --- /dev/null +++ b/doc/unexport.html @@ -0,0 +1,46 @@ + + + + + execline: the unexport command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The unexport program

+ +

+unexport removes a variable from the environment, then +executes a program. +

+ +

Interface

+ +
+     unexport var prog...
+
+ +

+unexport removes the var variable from the +environment, then execs into prog with +its arguments. +

+ +

Notes

+ + + + + diff --git a/doc/upgrade.html b/doc/upgrade.html new file mode 100644 index 0000000..9cd795b --- /dev/null +++ b/doc/upgrade.html @@ -0,0 +1,35 @@ + + + + + execline: how to upgrade + + + + + + +

+execline
+Software
+skarnet.org +

+ + +

to 2.0.0.0

+ + + + + diff --git a/doc/wait.html b/doc/wait.html new file mode 100644 index 0000000..680cd78 --- /dev/null +++ b/doc/wait.html @@ -0,0 +1,53 @@ + + + + + execline: the wait command + + + + + + +

+execline
+Software
+skarnet.org +

+ +

The wait program

+ +

+wait waits for a set of children, then executes a program. +

+ +

Interface

+ +

+ In an execlineb script: +

+ +
+     wait [ -r ] { [ pids... ] } prog...
+
+ + + +

Options

+ + + + + -- cgit v1.2.3