EXECLINE-SUBSTITUTE(7)

๐Ÿ“ฆ version 2.9.9.2, in nixpkgs unstable

๐Ÿ’– execline-substitute(7) ๐Ÿ’–

ok so first things first, bestie: this is EXECLINE-SUBSTITUTE(7), from the Miscellaneous Information Manual, and it's literally the whole vibe guide to execline variable substitution. come learn with me ๐Ÿซถ


โœจ NAME โœจ

execline-substitute โ€” the big-picture overview of execline variable substitution. like, the concept, not one single command. slay.


๐ŸŒธ DESCRIPTION ๐ŸŒธ

ok so picture this: in a shell, when you type

$ A='foobar' ; echo $A

the echo(1) command gets handed the argument foobar. the foobar value got substituted in place of the A variable. iconic behaviour honestly.

now here's the twist ๐ŸŒ€ โ€” execline keeps no state, so it has no real variables at all. but it still gives you that substitution facility, through substitution commands, namely:

a substitution command takes a key โ€” that's a string, and it can contain any character except $, { and }, though ngl it's recommended you stick to only alphanumerical characters โ€” plus a way to compute a value.

๐ŸŒผ Basics ๐ŸŒผ

if the substitution key is foo, then the substitution command is gonna look for every occurrence of ${foo} or $foo in the rest of its argv. heads up: ${foo}bar matches, but $foobar does not. so to be safe, always use the brace syntax unless $foo is a word all on its own. fr fr.

every match then gets replaced with the value. ๐Ÿ’ซ

the simplest example is this:

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

which replaces the FOO key with the blah value, then executes the echo(1) command. so that script prints blah on stdout. easy!

๐ŸŽ€ Quoting ๐ŸŽ€

execline lets you write literal ${foo} constructs even while the foo variable is actively being substituted โ€” that's the quoting mechanism doing its thing. brace (pun fully intended ๐Ÿ’…) yourself: this next bit is the most complex part of the entire language. no cap.

Rationale

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

  • the ${foo} sequence has to mean one of two things: be substituted, or don't be substituted.
  • the default (unquoted) action should be: substitute.
  • a sequence that means "do not substitute" should be able to appear literally. and the quote character should also be able to appear literally before a sequence that means "substitute". (tricky, eh? ๐Ÿ˜ญ)
  • there should be as few quote characters as possible, to dodge all those shell-like quoting nightmares.

Syntax

the rule, bestie:

  • the backslash (\) is a quote character for substitution commands.
  • the following rule applies only if the foo key is explicitly used in a substitution command. if no command tries to substitute anything for foo, sequences like ${foo} and any preceding backslashes are left completely untouched.
  • (Substitute.) if ${foo} is preceded by 2*n backslashes (an even number), the whole sequence gets replaced with n backslashes, followed by the substituted value.
  • (Do not substitute.) if ${foo} is preceded by 2*n+1 backslashes (an odd number), the whole sequence gets replaced with n backslashes, followed by the literal ${foo}.

and now the catch ๐Ÿซ  โ€” the execlineb(1) launcher, same as the shell, interprets backslashes as escape characters. so to make a word containing a backslash, you need to write two backslashes in your execline script or shell command line. which means the whole number of backslashes you write before your ${foo} sequence must be doubled so the substitution command reads the proper number of backslashes and does its job correctly.

once you keep that in mind, the quoting rule is honestly logical. i promise. ๐Ÿ’œ

Example

the quoting rule is best illustrated with this 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 gets substituted. it can be crunched, chomped, and/or split (cf. execline-transform(7)).

๐ŸŒˆ Substitution of split values ๐ŸŒˆ

a 'split' value for FOO means 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(1) command gets called with three arguments: prefix-v1-postfix, prefix-v2-postfix, and prefix-v3-postfix. chef's kiss ๐Ÿ‘‘

(implementation note, and this one's important: the fact that word prefixes are kept is exactly what makes execline's substitutions secure. blocks (cf. execline-block(7)) are implemented via prefix space characters; a substitution happening inside a block will always produce words beginning with the right amount of spaces, so substituted values can't prematurely terminate a block. ๐Ÿ”ฅ)

Recursive substitutions

a direct consequence of that rule: substitutions get performed recursively if more than one key appears in a single word and the values for those keys are split. parallel substitutions are performed left to right. for instance, in

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

the ${B}x${B} word gets replaced with nine words: 1x1, 1x2, 1x3, 2x1, 2x2, 2x3, 3x1, 3x2, and 3x3, in that order.

here's one with two distinct substitutions running 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 gets replaced with twelve words: ax1, ax2, ax3, bx1, bx2, bx3, cx1, cx2, cx3, dx1, dx2, and dx3, in that order. you can check for yourself that the order of the define directives in multisubstitute(1) does not matter. ๐Ÿ’ซ

if that left-to-right order doesn't 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 that will substitute ${B} first, then ${A}. so it prints

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've mastered the art of execline substitution, then you can try to do better than these people:

  • Joรซl Riou [1] wrote the first execlineb quine [2], using only echo(1) as a non-execline external command.
  • shortly after, Paul Jarc [3] wrote a much shorter quine [4], using echo(1) and env(1) as non-execline external commands. he also wrote a revised version [5], using only echo(1), and a shorter definitive version [6]. that last one is probably very close to the shortest possible execline quine.
  • David Madore [7] wrote another quine [8], using printf(1). his quine is longer than the other ones, but it's well-commented and can be used as a tutorial on how to write quines. :)

๐Ÿ‘‘ SEE ALSO ๐Ÿ‘‘

define(1), echo(1), elgetpositionals(1), elglob(1), env(1), execlineb(1), importas(1), multidefine(1), multisubstitute(1), multisubstitute(1), printf(1), execline-block(7), execline-transform(7)

(yes, multisubstitute(1) is listed twice in the original โ€” that's just how it is, i don't make the rules ๐Ÿ’…)

this man page is ported from the authoritative documentation at: https://skarnet.org/software/execline/el_substitute.html


๐ŸŒŸ AUTHORS ๐ŸŒŸ

Laurent Bercot Alexis <flexibeast@gmail.com> (man page port)


ok and that's the whole page, bestie, you ate it ๐Ÿ“

bye bye, go substitute some values responsibly!! ๐Ÿ’–โœจ this cutie came from Debian, dated April 16, 2024, and it's the one and only EXECLINE-SUBSTITUTE(7) from the Miscellaneous Information Manual โ€” see you in the next man page, mwah ๐Ÿ˜˜๐ŸŽ€

๐Ÿ“ฆ where this page comes from