summary refs log tree commit diff
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2020-12-30 23:06:31 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2020-12-30 23:06:31 +0000
commitf021f61f10c566fcae2f77b1a4b095869076062b (patch)
treece84d18f30a4ebf5f6dc3b7ea1b009ba1a06ffcf
parentb6b71f9942fb5f209e183c2ca997f33071c38c71 (diff)
downloadexecline-f021f61f10c566fcae2f77b1a4b095869076062b.tar.gz
execline-f021f61f10c566fcae2f77b1a4b095869076062b.tar.xz
execline-f021f61f10c566fcae2f77b1a4b095869076062b.zip
Add -E option for variable autoimport
-rw-r--r--doc/backtick.html14
-rw-r--r--doc/forbacktickx.html7
-rw-r--r--doc/forstdin.html7
-rw-r--r--doc/forx.html7
-rw-r--r--doc/getcwd.html12
-rw-r--r--doc/getpid.html12
-rw-r--r--doc/withstdinas.html7
-rw-r--r--package/deps.mak24
-rw-r--r--src/execline/backtick.c82
-rw-r--r--src/execline/deps-exe/getcwd1
-rw-r--r--src/execline/deps-exe/getpid1
-rw-r--r--src/execline/deps-exe/withstdinas1
-rw-r--r--src/execline/forbacktickx.c11
-rw-r--r--src/execline/forstdin.c114
-rw-r--r--src/execline/forx.c39
-rw-r--r--src/execline/getcwd.c36
-rw-r--r--src/execline/getpid.c38
-rw-r--r--src/execline/withstdinas.c59
-rw-r--r--src/include/execline/execline.h7
-rw-r--r--src/libexecline/deps-lib/execline2
-rw-r--r--src/libexecline/el_modif_and_exec.c36
-rw-r--r--src/libexecline/el_modif_and_spawn.c39
-rw-r--r--src/libexecline/el_spawn0.c1
23 files changed, 333 insertions, 224 deletions
diff --git a/doc/backtick.html b/doc/backtick.html
index 1f77432..91e963a 100644
--- a/doc/backtick.html
+++ b/doc/backtick.html
@@ -30,7 +30,7 @@ environment variable, then executes another program.
 </p>
 
 <pre>
-     backtick [ -i | -I | -D <em>default</em> ] [ -N | -n ] <em>variable</em> { <em>prog1...</em> } <em>prog2...</em>
+     backtick [ -i | -I | -D <em>default</em> ] [ -N | -n ] [ -E | -e ] <em>variable</em> { <em>prog1...</em> } <em>prog2...</em>
 </pre>
 
 <ul>
@@ -48,6 +48,11 @@ output as a value. </li>
 <ul>
  <li> <tt>-N</tt>&nbsp;: store <em>prog1...</em>'s output as is, including the last newline, if any. </li>
  <li> <tt>-n</tt>&nbsp;: chomp an ending newline off <em>prog1...</em>'s output. This is the default. </li>
+ <li> <tt>-e</tt>&nbsp;: no autoimport. This is the default. </li>
+ <li> <tt>-E</tt>&nbsp;: autoimport. Instead of exec'ing into
+<em>prog2...</em>, exec into <tt>importas -ui <em>variable</em> <em>variable</em>
+<em>prog2...</em></tt>. This substitutes <em>variable</em> into the command
+line instead of putting it into the environment. </li>
 </ul>
 
 <p>
@@ -69,12 +74,5 @@ or to whatever <em>prog1...</em> wrote before crashing;
 then execution proceeds. </li>
 </ul>
 
-<h2> Notes </h2>
-
-<ul>
- <li> You can start <em>prog2...</em> with "importas -u <em>variable</em> <em>variable</em>"
-to perform variable substitution. </li>
-</ul>
-
 </body>
 </html>
diff --git a/doc/forbacktickx.html b/doc/forbacktickx.html
index d28ad0b..cbf33b5 100644
--- a/doc/forbacktickx.html
+++ b/doc/forbacktickx.html
@@ -30,7 +30,7 @@ run another program.
 </p>
 
 <pre>
-     forbacktickx [ -p | -o <em>okcodes</em> | -x <em>breakcodes</em> ] [ -N | -n ] [ -C | -c ] [ -0 | -d <em>delim</em> ] <em>variable</em> { <em>gen...</em> } <em>loop...</em>
+     forbacktickx [ -E | -e ] [ -p | -o <em>okcodes</em> | -x <em>breakcodes</em> ] [ -N | -n ] [ -C | -c ] [ -0 | -d <em>delim</em> ] <em>variable</em> { <em>gen...</em> } <em>loop...</em>
 </pre>
 
 <ul>
@@ -65,6 +65,11 @@ not listed in <em>okcodes</em>, forbacktickx will exit immediately with an
 option, but with inverted meaning - the listed exit codes are codes
 that will make forbacktickx break the loop and exit, and the unlisted exit
 codes will make it keep looping. </li>
+ <li> <tt>-e</tt>&nbsp;: no autoimport. This is the default. </li>
+ <li> <tt>-E</tt>&nbsp;: autoimport. Instead of spawning
+<em>loop...</em>, spawn <tt>importas -ui <em>variable</em> <em>variable</em>
+<em>loop...</em></tt>. This substitutes <em>variable</em> into the command
+line instead of putting it into the environment. </li>
 </ul>
 
 <p>
diff --git a/doc/forstdin.html b/doc/forstdin.html
index 74644b4..3b00d7d 100644
--- a/doc/forstdin.html
+++ b/doc/forstdin.html
@@ -30,7 +30,7 @@ run another program.
 </p>
 
 <pre>
-     forstdin [ -p | -o <em>okcodes</em> | -x <em>breakcodes</em> ] [ -N | -n ] [ -C | -c ] [ -0 | -d <em>delim</em> ] <em>variable</em> <em>loop...</em>
+     forstdin [ -E | -e ] [ -p | -o <em>okcodes</em> | -x <em>breakcodes</em> ] [ -N | -n ] [ -C | -c ] [ -0 | -d <em>delim</em> ] <em>variable</em> <em>loop...</em>
 </pre>
 
 <ul>
@@ -61,6 +61,11 @@ not listed in <em>okcodes</em>, forstdin will exit immediately with an
 option, but with inverted meaning - the listed exit codes are codes
 that will make forstdin break the loop and exit, and the unlisted exit
 codes will make it keep looping. </li>
+ <li> <tt>-e</tt>&nbsp;: no autoimport. This is the default. </li>
+ <li> <tt>-E</tt>&nbsp;: autoimport. Instead of spawning
+<em>loop...</em>, spawn <tt>importas -ui <em>variable</em> <em>variable</em>
+<em>loop...</em></tt>. This substitutes <em>variable</em> into the command
+line instead of putting it into the environment. </li>
 </ul>
 
 <p>
diff --git a/doc/forx.html b/doc/forx.html
index 1c2a61c..8f1d558 100644
--- a/doc/forx.html
+++ b/doc/forx.html
@@ -29,7 +29,7 @@
 </p>
 
 <pre>
-     forx [ -p ] [ -o <em>okcodes</em> | -x <em>breakcodes</em> ] <em>variable</em> { <em>args...</em> } <em>loop...</em>
+     forx [ -E | -e ] [ -p ] [ -o <em>okcodes</em> | -x <em>breakcodes</em> ] <em>variable</em> { <em>args...</em> } <em>loop...</em>
 </pre>
 
 <ul>
@@ -63,6 +63,11 @@ will exit 0 if all of the exit codes are in the values listed in the <em>okcodes
 list, else it will exit 1. If the <tt>-x</tt> option has been given,
 <tt>forx</tt> will exit 0 if none of the exit codes are in the values
 listed in the <em>breakcodes</em> list, else it will exit 1. </li>
+ <li> <tt>-e</tt>&nbsp;: no autoimport. This is the default. </li>
+ <li> <tt>-E</tt>&nbsp;: autoimport. Instead of spawning
+<em>loop...</em>, spawn <tt>importas -ui <em>variable</em> <em>variable</em>
+<em>loop...</em></tt>. This substitutes <em>variable</em> into the command
+line instead of putting it into the environment. </li>
 </ul>
 
 <h2> Notes </h2>
diff --git a/doc/getcwd.html b/doc/getcwd.html
index 9735630..d3e7e27 100644
--- a/doc/getcwd.html
+++ b/doc/getcwd.html
@@ -27,7 +27,7 @@ then executes a program.
 <h2> Interface </h2>
 
 <pre>
-     getcwd <em>var</em> <em>prog...</em>
+     getcwd [ -E | -e ] <em>var</em> <em>prog...</em>
 </pre>
 
 <p>
@@ -37,6 +37,16 @@ into the <em>var</em> variable, then
 execs into <em>prog</em> with its arguments.
 </p>
 
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-e</tt>&nbsp;: no autoimport. This is the default. </li>
+ <li> <tt>-E</tt>&nbsp;: autoimport. Instead of exec'ing into
+<em>prog...</em>, exec into <tt>importas -ui <em>var</em> <em>var</em>
+<em>prog...</em></tt>. This substitutes <em>var</em> into the command
+line instead of putting it into the environment. </li>
+</ul>
+
 <h2> Notes </h2>
 
 <ul>
diff --git a/doc/getpid.html b/doc/getpid.html
index ca363df..5a849e8 100644
--- a/doc/getpid.html
+++ b/doc/getpid.html
@@ -26,7 +26,7 @@ then executes a program.
 <h2> Interface </h2>
 
 <pre>
-     getpid <em>var</em> <em>prog...</em>
+     getpid [ -E | -e ] <em>var</em> <em>prog...</em>
 </pre>
 
 <p>
@@ -34,6 +34,16 @@ then executes a program.
 execs into <em>prog</em> with its arguments.
 </p>
 
+<h2> Options </h2>
+
+<ul>
+ <li> <tt>-e</tt>&nbsp;: no autoimport. This is the default. </li>
+ <li> <tt>-E</tt>&nbsp;: autoimport. Instead of exec'ing into
+<em>prog...</em>, exec into <tt>importas -ui <em>var</em> <em>var</em>
+<em>prog...</em></tt>. This substitutes <em>var</em> into the command
+line instead of putting it into the environment. </li>
+</ul>
+
 <h2> Notes </h2>
 
 <ul>
diff --git a/doc/withstdinas.html b/doc/withstdinas.html
index ccd69d7..5b9e653 100644
--- a/doc/withstdinas.html
+++ b/doc/withstdinas.html
@@ -31,7 +31,7 @@ environment variable.
 </p>
 
 <pre>
-     withstdinas [ -i | -I | -D <em>default</em> ] [ -N | -n ] <em>variable</em> <em>prog...</em>
+     withstdinas [ -i | -I | -D <em>default</em> ] [ -N | -n ] [ -E | -e ] <em>variable</em> <em>prog...</em>
 </pre>
 
 <ul>
@@ -46,6 +46,11 @@ environment variable.
 <ul>
  <li> <tt>-N</tt>&nbsp;: do not chomp an ending newline off stdin. </li>
  <li> <tt>-n</tt>&nbsp;: chomp an ending newline off stdin. This is the default. </li>
+ <li> <tt>-e</tt>&nbsp;: no autoimport. This is the default. </li>
+ <li> <tt>-E</tt>&nbsp;: autoimport. Instead of exec'ing into
+<em>prog...</em>, exec into <tt>importas -ui <em>variable</em> <em>variable</em>
+<em>prog...</em></tt>. This substitutes <em>variable</em> into the command
+line instead of putting it into the environment. </li>
 </ul>
 
 <p>
diff --git a/package/deps.mak b/package/deps.mak
index 3aac760..6bfce8e 100644
--- a/package/deps.mak
+++ b/package/deps.mak
@@ -24,10 +24,10 @@ src/execline/fdreserve.o src/execline/fdreserve.lo: src/execline/fdreserve.c
 src/execline/fdswap.o src/execline/fdswap.lo: src/execline/fdswap.c
 src/execline/forbacktickx.o src/execline/forbacktickx.lo: src/execline/forbacktickx.c src/include/execline/config.h src/include/execline/execline.h
 src/execline/foreground.o src/execline/foreground.lo: src/execline/foreground.c src/include/execline/execline.h
-src/execline/forstdin.o src/execline/forstdin.lo: src/execline/forstdin.c src/include/execline/config.h src/include/execline/execline.h
+src/execline/forstdin.o src/execline/forstdin.lo: src/execline/forstdin.c src/include/execline/execline.h
 src/execline/forx.o src/execline/forx.lo: src/execline/forx.c src/include/execline/config.h src/include/execline/execline.h
-src/execline/getcwd.o src/execline/getcwd.lo: src/execline/getcwd.c
-src/execline/getpid.o src/execline/getpid.lo: src/execline/getpid.c
+src/execline/getcwd.o src/execline/getcwd.lo: src/execline/getcwd.c src/include/execline/execline.h
+src/execline/getpid.o src/execline/getpid.lo: src/execline/getpid.c src/include/execline/execline.h
 src/execline/heredoc.o src/execline/heredoc.lo: src/execline/heredoc.c
 src/execline/homeof.o src/execline/homeof.lo: src/execline/homeof.c
 src/execline/if.o src/execline/if.lo: src/execline/if.c src/include/execline/execline.h
@@ -46,10 +46,12 @@ src/execline/shift.o src/execline/shift.lo: src/execline/shift.c src/include/exe
 src/execline/trap.o src/execline/trap.lo: src/execline/trap.c src/include/execline/execline.h
 src/execline/tryexec.o src/execline/tryexec.lo: src/execline/tryexec.c src/include/execline/execline.h
 src/execline/unexport.o src/execline/unexport.lo: src/execline/unexport.c
-src/execline/wait.o src/execline/wait.lo: src/execline/wait.c src/include/execline/execline.h
-src/execline/withstdinas.o src/execline/withstdinas.lo: src/execline/withstdinas.c
+src/execline/wait.o src/execline/wait.lo: src/execline/wait.c src/include/execline/config.h src/include/execline/execline.h
+src/execline/withstdinas.o src/execline/withstdinas.lo: src/execline/withstdinas.c src/include/execline/execline.h
 src/libexecline/el_execsequence.o src/libexecline/el_execsequence.lo: src/libexecline/el_execsequence.c src/include/execline/execline.h
 src/libexecline/el_getstrict.o src/libexecline/el_getstrict.lo: src/libexecline/el_getstrict.c src/include/execline/execline.h
+src/libexecline/el_modif_and_exec.o src/libexecline/el_modif_and_exec.lo: src/libexecline/el_modif_and_exec.c src/include/execline/config.h src/include/execline/execline.h
+src/libexecline/el_modif_and_spawn.o src/libexecline/el_modif_and_spawn.lo: src/libexecline/el_modif_and_spawn.c src/include/execline/config.h src/include/execline/execline.h
 src/libexecline/el_parse.o src/libexecline/el_parse.lo: src/libexecline/el_parse.c src/include/execline/execline.h
 src/libexecline/el_parse_from_buffer.o src/libexecline/el_parse_from_buffer.lo: src/libexecline/el_parse_from_buffer.c src/include/execline/execline.h
 src/libexecline/el_parse_from_string.o src/libexecline/el_parse_from_string.lo: src/libexecline/el_parse_from_string.c src/include/execline/execline.h
@@ -123,9 +125,9 @@ forstdin: src/execline/forstdin.o ${LIBEXECLINE}
 forx: EXTRA_LIBS := -lskarnet ${SPAWN_LIB}
 forx: src/execline/forx.o ${LIBEXECLINE}
 getcwd: EXTRA_LIBS := -lskarnet
-getcwd: src/execline/getcwd.o
+getcwd: src/execline/getcwd.o ${LIBEXECLINE}
 getpid: EXTRA_LIBS := -lskarnet
-getpid: src/execline/getpid.o
+getpid: src/execline/getpid.o ${LIBEXECLINE}
 heredoc: EXTRA_LIBS := -lskarnet
 heredoc: src/execline/heredoc.o
 homeof: EXTRA_LIBS := -lskarnet ${MAYBEPTHREAD_LIB}
@@ -165,14 +167,14 @@ unexport: src/execline/unexport.o
 wait: EXTRA_LIBS := -lskarnet
 wait: src/execline/wait.o ${LIBEXECLINE}
 withstdinas: EXTRA_LIBS := -lskarnet
-withstdinas: src/execline/withstdinas.o
+withstdinas: src/execline/withstdinas.o ${LIBEXECLINE}
 ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),)
-libexecline.a.xyzzy: src/libexecline/el_execsequence.o src/libexecline/el_getstrict.o src/libexecline/el_parse.o src/libexecline/el_parse_from_buffer.o src/libexecline/el_parse_from_string.o src/libexecline/el_popenv.o src/libexecline/el_pushenv.o src/libexecline/el_semicolon.o src/libexecline/el_spawn0.o src/libexecline/el_spawn1.o src/libexecline/el_substandrun.o src/libexecline/el_substandrun_str.o src/libexecline/el_substitute.o src/libexecline/el_transform.o src/libexecline/el_vardupl.o src/libexecline/exlsn_define.o src/libexecline/exlsn_elglob.o src/libexecline/exlsn_importas.o src/libexecline/exlsn_multidefine.o src/libexecline/exlsn_exlp.o src/libexecline/exlsn_main.o src/libexecline/exlsn_free.o src/libexecline/exlp.o
+libexecline.a.xyzzy: src/libexecline/el_execsequence.o src/libexecline/el_getstrict.o src/libexecline/el_modif_and_exec.o src/libexecline/el_modif_and_spawn.o src/libexecline/el_parse.o src/libexecline/el_parse_from_buffer.o src/libexecline/el_parse_from_string.o src/libexecline/el_popenv.o src/libexecline/el_pushenv.o src/libexecline/el_semicolon.o src/libexecline/el_spawn0.o src/libexecline/el_spawn1.o src/libexecline/el_substandrun.o src/libexecline/el_substandrun_str.o src/libexecline/el_substitute.o src/libexecline/el_transform.o src/libexecline/el_vardupl.o src/libexecline/exlsn_define.o src/libexecline/exlsn_elglob.o src/libexecline/exlsn_importas.o src/libexecline/exlsn_multidefine.o src/libexecline/exlsn_exlp.o src/libexecline/exlsn_main.o src/libexecline/exlsn_free.o src/libexecline/exlp.o
 else
-libexecline.a.xyzzy: src/libexecline/el_execsequence.lo src/libexecline/el_getstrict.lo src/libexecline/el_parse.lo src/libexecline/el_parse_from_buffer.lo src/libexecline/el_parse_from_string.lo src/libexecline/el_popenv.lo src/libexecline/el_pushenv.lo src/libexecline/el_semicolon.lo src/libexecline/el_spawn0.lo src/libexecline/el_spawn1.lo src/libexecline/el_substandrun.lo src/libexecline/el_substandrun_str.lo src/libexecline/el_substitute.lo src/libexecline/el_transform.lo src/libexecline/el_vardupl.lo src/libexecline/exlsn_define.lo src/libexecline/exlsn_elglob.lo src/libexecline/exlsn_importas.lo src/libexecline/exlsn_multidefine.lo src/libexecline/exlsn_exlp.lo src/libexecline/exlsn_main.lo src/libexecline/exlsn_free.lo src/libexecline/exlp.lo
+libexecline.a.xyzzy: src/libexecline/el_execsequence.lo src/libexecline/el_getstrict.lo src/libexecline/el_modif_and_exec.lo src/libexecline/el_modif_and_spawn.lo src/libexecline/el_parse.lo src/libexecline/el_parse_from_buffer.lo src/libexecline/el_parse_from_string.lo src/libexecline/el_popenv.lo src/libexecline/el_pushenv.lo src/libexecline/el_semicolon.lo src/libexecline/el_spawn0.lo src/libexecline/el_spawn1.lo src/libexecline/el_substandrun.lo src/libexecline/el_substandrun_str.lo src/libexecline/el_substitute.lo src/libexecline/el_transform.lo src/libexecline/el_vardupl.lo src/libexecline/exlsn_define.lo src/libexecline/exlsn_elglob.lo src/libexecline/exlsn_importas.lo src/libexecline/exlsn_multidefine.lo src/libexecline/exlsn_exlp.lo src/libexecline/exlsn_main.lo src/libexecline/exlsn_free.lo src/libexecline/exlp.lo
 endif
 libexecline.so.xyzzy: EXTRA_LIBS := -lskarnet
-libexecline.so.xyzzy: src/libexecline/el_execsequence.lo src/libexecline/el_getstrict.lo src/libexecline/el_parse.lo src/libexecline/el_parse_from_buffer.lo src/libexecline/el_parse_from_string.lo src/libexecline/el_popenv.lo src/libexecline/el_pushenv.lo src/libexecline/el_semicolon.lo src/libexecline/el_spawn0.lo src/libexecline/el_spawn1.lo src/libexecline/el_substandrun.lo src/libexecline/el_substandrun_str.lo src/libexecline/el_substitute.lo src/libexecline/el_transform.lo src/libexecline/el_vardupl.lo src/libexecline/exlsn_define.lo src/libexecline/exlsn_elglob.lo src/libexecline/exlsn_importas.lo src/libexecline/exlsn_multidefine.lo src/libexecline/exlsn_exlp.lo src/libexecline/exlsn_main.lo src/libexecline/exlsn_free.lo src/libexecline/exlp.lo
+libexecline.so.xyzzy: src/libexecline/el_execsequence.lo src/libexecline/el_getstrict.lo src/libexecline/el_modif_and_exec.lo src/libexecline/el_modif_and_spawn.lo src/libexecline/el_parse.lo src/libexecline/el_parse_from_buffer.lo src/libexecline/el_parse_from_string.lo src/libexecline/el_popenv.lo src/libexecline/el_pushenv.lo src/libexecline/el_semicolon.lo src/libexecline/el_spawn0.lo src/libexecline/el_spawn1.lo src/libexecline/el_substandrun.lo src/libexecline/el_substandrun_str.lo src/libexecline/el_substitute.lo src/libexecline/el_transform.lo src/libexecline/el_vardupl.lo src/libexecline/exlsn_define.lo src/libexecline/exlsn_elglob.lo src/libexecline/exlsn_importas.lo src/libexecline/exlsn_multidefine.lo src/libexecline/exlsn_exlp.lo src/libexecline/exlsn_main.lo src/libexecline/exlsn_free.lo src/libexecline/exlp.lo
 posix-cd: EXTRA_LIBS := -lskarnet
 posix-cd: src/posix/posix-cd.o
 posix-umask: EXTRA_LIBS := -lskarnet
diff --git a/src/execline/backtick.c b/src/execline/backtick.c
index fa7403f..9394456 100644
--- a/src/execline/backtick.c
+++ b/src/execline/backtick.c
@@ -12,22 +12,22 @@
 
 #include <execline/execline.h>
 
-#define USAGE "backtick [ -i | -I | -D default ] [ -N | -n ] var { prog... } remainder..."
+#define USAGE "backtick [ -i | -I | -D default ] [ -N | -n ] [ -E | -e ] var { prog... } remainder..."
 #define dieusage() strerr_dieusage(100, USAGE)
 
 int main (int argc, char const **argv, char const *const *envp)
 {
   subgetopt_t localopt = SUBGETOPT_ZERO ;
-  pid_t pid ;
   int argc1, fdwstat ;
-  stralloc modif = STRALLOC_ZERO ;
-  size_t modifstart ;
-  int insist = 0, chomp = 1 ;
+  stralloc value = STRALLOC_ZERO ;
+  char const *var ;
+  char const *val ;
+  int insist = 0, chomp = 1, doimport = 0 ;
   char const *def = 0 ;
   PROG = "backtick" ;
   for (;;)
   {
-    int opt = subgetopt_r(argc, argv, "iINnD:", &localopt) ;
+    int opt = subgetopt_r(argc, argv, "iINnD:Ee", &localopt) ;
     if (opt < 0) break ;
     switch (opt)
     {
@@ -36,69 +36,51 @@ int main (int argc, char const **argv, char const *const *envp)
       case 'N' : chomp = 0 ; break ;
       case 'n' : chomp = 1 ; break ;
       case 'D' : def = localopt.arg ; break ;
+      case 'E' : doimport = 1 ; break ;
+      case 'e' : doimport = 0 ; break ;
       default : dieusage() ;
     }
   }
   argc -= localopt.ind ; argv += localopt.ind ;
 
   if (argc < 2) dieusage() ;
-  if (!*argv[0]) strerr_dief1x(100, "empty variable not accepted") ;
-  if (!stralloc_cats(&modif, argv[0]) || !stralloc_catb(&modif, "=", 1))
-    strerr_diefu1sys(111, "stralloc_catb") ;
-  modifstart = modif.len ;
-  argc-- ; argv++ ;
+  if (!argv[0][0] || strchr(argv[0], '=')) strerr_dief1x(100, "invalid variable name") ;
+  argc-- ; var = *argv++ ;
   argc1 = el_semicolon(argv) ;
   if (!argc1) strerr_dief1x(100, "empty block") ;
   if (argc1 >= argc) strerr_dief1x(100, "unterminated block") ;
-
   argv[argc1] = 0 ;
-  pid = child_spawn1_pipe(argv[0], argv, envp, &fdwstat, 1) ;
-  if (!pid) strerr_diefu2sys(111, "spawn ", argv[0]) ;
-  if (!slurp(&modif, fdwstat)) strerr_diefu1sys(111, "slurp") ;
-  close(fdwstat) ;
-  if (wait_pid(pid, &fdwstat) < 0) strerr_diefu1sys(111, "wait_pid") ;
 
+  {
+    pid_t pid = child_spawn1_pipe(argv[0], argv, envp, &fdwstat, 1) ;
+    if (!pid) strerr_diefu2sys(111, "spawn ", argv[0]) ;
+    if (!slurp(&value, fdwstat) || !stralloc_0(&value))
+      strerr_diefu1sys(111, "slurp") ;
+    close(fdwstat) ;
+    if (wait_pid(pid, &fdwstat) < 0) strerr_diefu1sys(111, "wait_pid") ;
+  }
+
+  val = value.s ;
   if (wait_status(fdwstat))
   {
     if (insist >= 2)
       if (WIFSIGNALED(fdwstat)) strerr_dief1x(111, "child process crashed") ;
       else strerr_dief1x(WEXITSTATUS(fdwstat), "child process exited non-zero") ;
-    else if (insist)
-    {
-      modif.len = modifstart - 1 ;
-      chomp = 0 ;
-    }
-    else if (def)
-    {
-      modif.len = modifstart ;
-      if (!stralloc_cats(&modif, def)) strerr_diefu1sys(111, "stralloc_catb") ;
-    }
+    else if (insist) val = 0 ;
+    else if (def) val = def ;
   }
-  if (argc1 == argc - 1) return 0 ;
-  if (!stralloc_0(&modif)) strerr_diefu1sys(111, "stralloc_catb") ;
+  else if (strlen(value.s) < value.len - 1)
   {
-    size_t reallen = strlen(modif.s) ;
-    if (reallen < modif.len - 1)
+    if (insist >= 2)
+      strerr_dief1x(1, "child process output contained a null character") ;
+    else if (insist) val = 0 ;
+    else if (def)
     {
-      if (insist >= 2)
-        strerr_dief1x(1, "child process output contained a null character") ;
-      else if (insist)
-      {
-        modif.len = modifstart ;
-        modif.s[modif.len - 1] = 0 ;
-        chomp = 0 ;
-      }
-      else if (def)
-      {
-        modif.len = modifstart ;
-        if (!stralloc_catb(&modif, def, strlen(def)+1))
-          strerr_diefu1sys(111, "stralloc_catb") ;
-        strerr_warnw2x("child process output contained a null character", " - using default instead") ;
-      }
-      else modif.len = reallen + 1 ;
+      val = def ;
+      strerr_warnw2x("child process output contained a null character", " - using default instead") ;
     }
-    if (chomp && (modif.s[modif.len - 2] == '\n'))
-      modif.s[--modif.len - 1] = 0 ;
   }
-  xmexec_en(argv + argc1 + 1, envp, modif.s, modif.len, 1) ;
+  else if (chomp && (value.s[value.len - 2] == '\n'))
+    value.s[--value.len - 1] = 0 ;
+  el_modif_and_exec(argv + argc1 + 1, var, val, doimport) ;
 }
diff --git a/src/execline/deps-exe/getcwd b/src/execline/deps-exe/getcwd
index e7187fe..97021b5 100644
--- a/src/execline/deps-exe/getcwd
+++ b/src/execline/deps-exe/getcwd
@@ -1 +1,2 @@
+${LIBEXECLINE}
 -lskarnet
diff --git a/src/execline/deps-exe/getpid b/src/execline/deps-exe/getpid
index e7187fe..97021b5 100644
--- a/src/execline/deps-exe/getpid
+++ b/src/execline/deps-exe/getpid
@@ -1 +1,2 @@
+${LIBEXECLINE}
 -lskarnet
diff --git a/src/execline/deps-exe/withstdinas b/src/execline/deps-exe/withstdinas
index e7187fe..97021b5 100644
--- a/src/execline/deps-exe/withstdinas
+++ b/src/execline/deps-exe/withstdinas
@@ -1 +1,2 @@
+${LIBEXECLINE}
 -lskarnet
diff --git a/src/execline/forbacktickx.c b/src/execline/forbacktickx.c
index 1f3a0f1..2fc8bb8 100644
--- a/src/execline/forbacktickx.c
+++ b/src/execline/forbacktickx.c
@@ -12,20 +12,20 @@
 #include <execline/config.h>
 #include <execline/execline.h>
 
-#define USAGE "forbacktickx [ -p | -o okcode,okcode,... | -x breakcode,breakcode,... ] [ -N | -n ] [ -C | -c ] [ -0 | -d delim ] var { backtickcmd... } command..."
+#define USAGE "forbacktickx [ -p | -o okcode,okcode,... | -x breakcode,breakcode,... ] [ -E | -e ] [ -N | -n ] [ -C | -c ] [ -0 | -d delim ] var { backtickcmd... } command..."
 #define dieusage() strerr_dieusage(100, USAGE)
 
 int main (int argc, char const *const *argv)
 {
   char const *delim = "\n" ;
   char const *codes = 0 ;
-  int crunch = 0, chomp = 1, not = 1, par = 0 ;
+  int crunch = 0, chomp = 1, not = 1, par = 0, doimport = 0 ;
   PROG = "forbacktickx" ;
   {
     subgetopt_t l = SUBGETOPT_ZERO ;
     for (;;)
     {
-      int opt = subgetopt_r(argc, argv, "pNnCc0d:o:x:", &l) ;
+      int opt = subgetopt_r(argc, argv, "pNnCc0d:o:x:Ee", &l) ;
       if (opt == -1) break ;
       switch (opt)
       {
@@ -54,6 +54,8 @@ int main (int argc, char const *const *argv)
           not = 1 ;
           break ;
         }
+        case 'E' : doimport = 1 ; break ;
+        case 'e' : doimport = 0 ; break ;
         default : dieusage() ;
       }
     }
@@ -65,7 +67,7 @@ int main (int argc, char const *const *argv)
   {
     unsigned int m = 0, i = 1 ;
     int fd = dup(0) ;
-    char const *newargv[argc + 18] ;
+    char const *newargv[argc + 19] ;
     char fmt[UINT_FMT] ;
     if (fd < 0)
     {
@@ -81,6 +83,7 @@ int main (int argc, char const *const *argv)
     newargv[m++] = EXECLINE_BINPREFIX "unexport" ;
     newargv[m++] = "!" ;
     newargv[m++] = EXECLINE_BINPREFIX "forstdin" ;
+    newargv[m++] = doimport ? "-E" : "-e" ;
     if (par) newargv[m++] = "-p" ;
     newargv[m++] = chomp ? "-n" : "-N" ;
     if (crunch) newargv[m++] = "-C" ;
diff --git a/src/execline/forstdin.c b/src/execline/forstdin.c
index 336aaa4..bacb1ae 100644
--- a/src/execline/forstdin.c
+++ b/src/execline/forstdin.c
@@ -9,16 +9,14 @@
 #include <skalibs/strerr2.h>
 #include <skalibs/stralloc.h>
 #include <skalibs/genalloc.h>
-#include <skalibs/env.h>
 #include <skalibs/sig.h>
 #include <skalibs/djbunix.h>
 #include <skalibs/skamisc.h>
 #include <skalibs/netstring.h>
 
-#include <execline/config.h>
 #include <execline/execline.h>
 
-#define USAGE "forstdin [ -p | -o okcode,okcode,... | -x breakcode,breakcode,... ] [ -N | -n ] [ -C | -c ] [ -0 | -d delim ] var command..."
+#define USAGE "forstdin [ -E | -e ] [ -p | -o okcode,okcode,... | -x breakcode,breakcode,... ] [ -N | -n ] [ -C | -c ] [ -0 | -d delim ] var command..."
 #define dieusage() strerr_dieusage(100, USAGE)
 
 static genalloc pids = GENALLOC_ZERO ; /* pid_t */
@@ -45,19 +43,20 @@ static void parallel_sigchld_handler (int sig)
   (void)sig ;
 }
 
-int main (int argc, char const **argv, char const *const *envp)
+int main (int argc, char const **argv)
 {
+  stralloc value = STRALLOC_ZERO ;
   char const *delim = "\n" ;
   size_t delimlen = 1 ;
   size_t nbc = 0 ;
   unsigned short okcodes[256] ;
-  int crunch = 0, chomp = 1, not = 1, eofcode = 1 ;
+  int crunch = 0, chomp = 1, not = 1, eofcode = 1, doimport = 0 ;
   PROG = "forstdin" ;
   {
     subgetopt_t l = SUBGETOPT_ZERO ;
     for (;;)
     {
-      int opt = subgetopt_r(argc, argv, "pNnCc0d:o:x:", &l) ;
+      int opt = subgetopt_r(argc, argv, "pNnCc0d:o:x:Ee", &l) ;
       if (opt == -1) break ;
       switch (opt)
       {
@@ -81,81 +80,74 @@ int main (int argc, char const **argv, char const *const *envp)
           not = 1 ;
           if (!ushort_scanlist(okcodes, 256, l.arg, &nbc)) dieusage() ;
           break ;
+        case 'E' : doimport = 1 ; break ;
+        case 'e' : doimport = 0 ; break ;
         default : dieusage() ;
       }
     }
     argc -= l.ind ; argv += l.ind ;
   }
   if (argc < 2) dieusage() ;
+  if (!argv[0][0] || strchr(argv[0], '=')) strerr_dief1x(100, "invalid variable name") ;
+
+  if (pids.s)
   {
-    stralloc modif = STRALLOC_ZERO ;
-    size_t envlen = env_len(envp) ;
-    size_t modifstart = strlen(argv[0]) + 1 ;
-    char const *newenv[envlen + 2] ;
-    if (!stralloc_ready(&modif, modifstart+1))
-      strerr_diefu1sys(111, "stralloc_ready") ;
-    memcpy(modif.s, argv[0], modifstart - 1) ;
-    modif.s[modifstart-1] = '=' ;
-    if (pids.s)
-    {
-      if (sig_catch(SIGCHLD, &parallel_sigchld_handler) < 0)
-        strerr_diefu1sys(111, "install SIGCHLD handler") ;
-    }
-    for (;;)
+    if (sig_catch(SIGCHLD, &parallel_sigchld_handler) < 0)
+      strerr_diefu1sys(111, "install SIGCHLD handler") ;
+  }
+  for (;;)
+  {
+    pid_t pid ;
+    value.len = 0 ;
+    if (delimlen)
     {
-      pid_t pid ;
-      modif.len = modifstart ;
-      if (delimlen)
-      {
-        int r = skagetlnsep(buffer_0, &modif, delim, delimlen) ;
-        if (!r) break ;
-        else if (r < 0)
-        {
-          if (errno != EPIPE) strerr_diefu1sys(111, "skagetlnsep") ;
-          if (chomp) break ;
-        }
-        if (crunch && modif.len == modifstart + 1) continue ;
-        if (chomp) modif.len-- ;
-      }
-      else
+      int r = skagetlnsep(buffer_0, &value, delim, delimlen) ;
+      if (!r) break ;
+      else if (r < 0)
       {
-        size_t unread = 0 ;
-        if (netstring_get(buffer_0, &modif, &unread) <= 0)
-        {
-          if (netstring_okeof(buffer_0, unread)) break ;
-          else strerr_diefu1sys(111, "netstring_get") ;
-        }
-      }
-      eofcode = 0 ;
-      if (!stralloc_0(&modif)) strerr_diefu1sys(111, "stralloc_0") ;
-      if (!env_mergen(newenv, envlen+2, envp, envlen, modif.s, modif.len, 1))
-        strerr_diefu1sys(111, "merge environment") ;
-      if (pids.s) sig_block(SIGCHLD) ;
-      pid = el_spawn0(argv[1], argv + 1, newenv) ;
-      if (!pid) strerr_diefu2sys(111, "spawn ", argv[1]) ;
-      if (pids.s)
-      {
-        if (!genalloc_append(pid_t, &pids, &pid))
-          strerr_diefu1sys(111, "genalloc_append") ;
-        sig_unblock(SIGCHLD) ;
+        if (errno != EPIPE) strerr_diefu1sys(111, "skagetlnsep") ;
+        if (chomp) break ;
       }
-      else
+      if (crunch && value.len == 1) continue ;
+      if (chomp) value.len-- ;
+    }
+    else
+    {
+      size_t unread = 0 ;
+      if (netstring_get(buffer_0, &value, &unread) <= 0)
       {
-        int wstat ;
-        if (wait_pid(pid, &wstat) < 0)
-          strerr_diefu2sys(111, "wait for ", argv[1]) ;
-        if (not == isok(okcodes, nbc, wait_estatus(wstat)))
-          return wait_estatus(wstat) ;
+        if (netstring_okeof(buffer_0, unread)) break ;
+        else strerr_diefu1sys(111, "netstring_get") ;
       }
     }
-    stralloc_free(&modif) ;
+    eofcode = 0 ;
+    if (!stralloc_0(&value)) strerr_diefu1sys(111, "stralloc_0") ;
+    if (pids.s) sig_block(SIGCHLD) ;
+    pid = el_modif_and_spawn(argv + 1, argv[0], value.s, doimport) ;
+    if (!pid) strerr_diefu2sys(111, "spawn ", argv[1]) ;
+    if (pids.s)
+    {
+      if (!genalloc_append(pid_t, &pids, &pid))
+        strerr_diefu1sys(111, "genalloc_append") ;
+      sig_unblock(SIGCHLD) ;
+    }
+    else
+    {
+      int wstat ;
+      if (wait_pid(pid, &wstat) < 0)
+        strerr_diefu2sys(111, "wait for ", argv[1]) ;
+      if (not == isok(okcodes, nbc, wait_estatus(wstat)))
+        return wait_estatus(wstat) ;
+    }
   }
   if (pids.s)
+  {
     for (;;)
     {
       sig_block(SIGCHLD) ;
       if (!pids.len) break ;
       sig_pause() ;
     }
+  }
   return eofcode ;
 }
diff --git a/src/execline/forx.c b/src/execline/forx.c
index be03794..8e6659b 100644
--- a/src/execline/forx.c
+++ b/src/execline/forx.c
@@ -13,7 +13,7 @@
 #include <execline/config.h>
 #include <execline/execline.h>
 
-#define USAGE "forx [ -p ] [ -o okcode,okcode,... | -x breakcode,breakcode,... ] var { values... } command..."
+#define USAGE "forx [ -E | -e ] [ -p ] [ -o okcode,okcode,... | -x breakcode,breakcode,... ] var { values... } command..."
 #define dieusage() strerr_dieusage(100, USAGE)
 
 static int isok (unsigned short const *tab, unsigned int n, int code)
@@ -42,19 +42,19 @@ static int waitn_code (unsigned short const *tab, unsigned int nbc, pid_t *pids,
   return ok ;
 }
 
-int main (int argc, char const **argv, char const *const *envp)
+int main (int argc, char const **argv)
 {
-  char const *x ;
-  int argc1 ;
+  char const *var ;
   unsigned short okcodes[256] ;
   size_t nbc = 0 ;
-  int flagpar = 0, not = 1 ;
+  int flagpar = 0, not = 1, doimport = 0 ;
+  unsigned int argc1 ;
   PROG = "forx" ;
   {
     subgetopt_t l = SUBGETOPT_ZERO ;
     for (;;)
     {
-      int opt = subgetopt_r(argc, argv, "po:x:", &l) ;
+      int opt = subgetopt_r(argc, argv, "po:x:Ee", &l) ;
       if (opt == -1) break ;
       switch (opt)
       {
@@ -67,6 +67,8 @@ int main (int argc, char const **argv, char const *const *envp)
           not = 1 ;
           if (!ushort_scanlist(okcodes, 256, l.arg, &nbc)) dieusage() ;
           break ;
+        case 'E' : doimport = 1 ; break ;
+        case 'e' : doimport = 0 ; break ;
         default : dieusage() ;
       }
     }
@@ -74,32 +76,17 @@ int main (int argc, char const **argv, char const *const *envp)
   }
 
   if (argc < 2) dieusage() ;
-  x = argv[0] ; if (!*x) dieusage() ;
-  if (x[0] == EXECLINE_BLOCK_QUOTE_CHAR)
-    strerr_warnw3x("variable ", x, " starts with a block quoting character") ;
-  argv++ ; argc-- ;
+  if (!argv[0][0] || strchr(argv[0], '=')) strerr_dief1x(100, "invalid variable name") ;
+  var = *argv++ ; argc-- ;
   argc1 = el_semicolon(argv) ;
   if (argc1 >= argc) strerr_dief1x(100, "unterminated block") ;
   if (!argc1 || (argc1 + 1 == argc)) return 0 ;
+
   {
-    size_t envlen = env_len(envp) ;
-    size_t varlen = strlen(x) ;
-    unsigned int i = 0 ;
     pid_t pids[flagpar ? argc1 : 1] ;
-    char const *newenv[envlen + 2] ;
-
-    for (; i < (unsigned int)argc1 ; i++)
+    for (unsigned int i = 0 ; i < argc1 ; i++)
     {
-      pid_t pid ;
-      size_t vallen = strlen(argv[i]) ;
-      char modif[varlen + vallen + 2] ;
-      memcpy(modif, x, varlen) ;
-      modif[varlen] = '=' ;
-      memcpy(modif + varlen + 1, argv[i], vallen) ;
-      modif[varlen + vallen + 1] = 0 ;
-      if (!env_mergen(newenv, envlen + 2, envp, envlen, modif, varlen + vallen + 2, 1))
-        strerr_diefu1sys(111, "build new environment") ;
-      pid = el_spawn0(argv[argc1+1], argv + argc1 + 1, newenv) ;
+      pid_t pid = el_modif_and_spawn(argv + argc1 + 1, var, argv[i], doimport) ;
       if (!pid) strerr_diefu2sys(111, "spawn ", argv[argc1+1]) ;
       if (flagpar) pids[i] = pid ;
       else
diff --git a/src/execline/getcwd.c b/src/execline/getcwd.c
index d41bd5a..2a82924 100644
--- a/src/execline/getcwd.c
+++ b/src/execline/getcwd.c
@@ -2,23 +2,39 @@
 
 #include <string.h>
 
+#include <skalibs/sgetopt.h>
 #include <skalibs/strerr2.h>
 #include <skalibs/stralloc.h>
 #include <skalibs/djbunix.h>
-#include <skalibs/exec.h>
 
-#define USAGE "getcwd variable prog..."
+#include <execline/execline.h>
+
+#define USAGE "getcwd [ -E | -e ] variable prog..."
+#define dieusage() strerr_dieusage(100, USAGE)
 
 int main (int argc, char const *const *argv)
 {
+  int doimport = 0 ;
   stralloc sa = STRALLOC_ZERO ;
   PROG = "getcwd" ;
-  if (argc < 3) strerr_dieusage(100, USAGE) ;
-  if (strchr(argv[1], '='))
-    strerr_dief2x(100, "invalid variable name: ", argv[1]) ;
-  if (!stralloc_cats(&sa, argv[1]) || !stralloc_catb(&sa, "=", 1))
-    strerr_diefu1sys(111, "stralloc_catb") ;
-  if (sagetcwd(&sa) < 0) strerr_diefu1sys(111, "getcwd") ;
-  if (!stralloc_0(&sa)) strerr_diefu1sys(111, "stralloc_catb") ;
-  xmexec_n(argv + 2, sa.s, sa.len, 1) ;
+  {
+    subgetopt_t l = SUBGETOPT_ZERO ;
+    for (;;)
+    {
+      int opt = subgetopt_r(argc, argv, "Ee", &l) ;
+      if (opt == -1) break ;
+      switch (opt)
+      {
+        case 'E' : doimport = 1 ; break ;
+        case 'e' : doimport = 0 ; break ;
+        default : dieusage() ;
+      }
+    }
+    argc -= l.ind ; argv += l.ind ;
+  }
+  if (argc < 2) dieusage() ;
+  if (!argv[0][0] || strchr(argv[0], '=')) strerr_dief1x(100, "invalid variable name") ;
+
+  if (sagetcwd(&sa) < 0 || !stralloc_0(&sa)) strerr_diefu1sys(111, "getcwd") ;
+  el_modif_and_exec(argv + 1, argv[0], sa.s, doimport) ;
 }
diff --git a/src/execline/getpid.c b/src/execline/getpid.c
index 06c4aaf..64866de 100644
--- a/src/execline/getpid.c
+++ b/src/execline/getpid.c
@@ -4,25 +4,37 @@
 #include <unistd.h>
 
 #include <skalibs/types.h>
+#include <skalibs/sgetopt.h>
 #include <skalibs/strerr2.h>
-#include <skalibs/exec.h>
 
-#define USAGE "getpid variable prog..."
+#include <execline/execline.h>
+
+#define USAGE "getpid [ -E | -e ] variable prog..."
+#define dieusage() strerr_dieusage(100, USAGE)
 
 int main (int argc, char const *const *argv)
 {
-  size_t len ;
+  int doimport = 0 ;
+  char fmt[PID_FMT] ;
   PROG = "getpid" ;
-  if (argc < 3) strerr_dieusage(100, USAGE) ;
-  len = strlen(argv[1]) ;
-  if (memchr(argv[1], '=', len))
-    strerr_dief2x(100, "invalid variable name: ", argv[1]) ;
   {
-    size_t i = len+1 ;
-    char fmt[PID_FMT + len + 2] ;
-    memcpy(fmt, argv[1], len) ;
-    fmt[len] = '=' ;
-    i += pid_fmt(fmt+i, getpid()) ; fmt[i++] = 0 ;
-    xmexec_n(argv+2, fmt, i, 1) ;
+    subgetopt_t l = SUBGETOPT_ZERO ;
+    for (;;)
+    {
+      int opt = subgetopt_r(argc, argv, "Ee", &l) ;
+      if (opt == -1) break ;
+      switch (opt)
+      {
+        case 'E' : doimport = 1 ; break ;
+        case 'e' : doimport = 0 ; break ;
+        default : dieusage() ;
+      }
+    }
+    argc -= l.ind ; argv += l.ind ;
   }
+  if (argc < 2) dieusage() ;
+  if (!argv[0][0] || strchr(argv[0], '=')) strerr_dief1x(100, "invalid variable name") ;
+
+  fmt[pid_fmt(fmt, getpid())] = 0 ;
+  el_modif_and_exec(argv + 1, argv[0], fmt, doimport) ;
 }
diff --git a/src/execline/withstdinas.c b/src/execline/withstdinas.c
index 467b68b..cd025bf 100644
--- a/src/execline/withstdinas.c
+++ b/src/execline/withstdinas.c
@@ -6,22 +6,23 @@
 #include <skalibs/strerr2.h>
 #include <skalibs/stralloc.h>
 #include <skalibs/djbunix.h>
-#include <skalibs/exec.h>
 
-#define USAGE "withstdinas [ -i | -I | -D default ] [ -N | -n ] var remainder..."
+#include <execline/execline.h>
+
+#define USAGE "withstdinas [ -i | -I | -D default ] [ -N | -n ] [ -E | -e ] var remainder..."
 #define dieusage() strerr_dieusage(100, USAGE)
 
-int main (int argc, char const **argv)
+int main (int argc, char const *const *argv)
 {
   subgetopt_t localopt = SUBGETOPT_ZERO ;
-  stralloc modif = STRALLOC_ZERO ;
-  size_t modifstart ;
-  int insist = 0, chomp = 1 ;
+  stralloc value = STRALLOC_ZERO ;
+  int insist = 0, chomp = 1, doimport = 0 ;
   char const *def = 0 ;
+  char const *val ;
   PROG = "withstdinas" ;
   for (;;)
   {
-    int opt = subgetopt_r(argc, argv, "iINnD:", &localopt) ;
+    int opt = subgetopt_r(argc, argv, "iINnD:Ee", &localopt) ;
     if (opt < 0) break ;
     switch (opt)
     {
@@ -30,41 +31,29 @@ int main (int argc, char const **argv)
       case 'N' : chomp = 0 ; break ;
       case 'n' : chomp = 1 ; break ;
       case 'D' : def = localopt.arg ; break ;
+      case 'E' : doimport = 1 ; break ;
+      case 'e' : doimport = 0 ; break ;
       default : dieusage() ;
     }
   }
   argc -= localopt.ind ; argv += localopt.ind ;
-
   if (!argc) dieusage() ;
-  if (!*argv[0] || strchr(argv[0], '=')) strerr_dief1x(100, "invalid variable name") ;
-  if (!stralloc_cats(&modif, argv[0]) || !stralloc_catb(&modif, "=", 1))
-    strerr_diefu1sys(111, "stralloc_catb") ;
-  modifstart = modif.len ;
-  if (!slurp(&modif, 0)) strerr_diefu1sys(111, "slurp") ;
-  if (!stralloc_0(&modif)) strerr_diefu1sys(111, "stralloc_catb") ;
+  if (!argv[0][0] || strchr(argv[0], '=')) strerr_dief1x(100, "invalid variable name") ;
+
+  if (!slurp(&value, 0) || !stralloc_0(&value)) strerr_diefu1sys(111, "slurp") ;
+  val = value.s ;
+  if (strlen(value.s) < value.len - 1)
   {
-    size_t reallen = strlen(modif.s) ;
-    if (reallen < modif.len - 1)
+    if (insist >= 2)
+      strerr_dief1x(1, "stdin contained a null character") ;
+    else if (insist) val = 0 ;
+    else if (def)
     {
-      if (insist >= 2)
-        strerr_dief1x(1, "stdin contained a null character") ;
-      else if (insist)
-      {
-        modif.len = modifstart ;
-        modif.s[modif.len - 1] = 0 ;
-        chomp = 0 ;
-      }
-      else if (def)
-      {
-        modif.len = modifstart ;
-        if (!stralloc_catb(&modif, def, strlen(def)+1))
-          strerr_diefu1sys(111, "stralloc_catb") ;
-        strerr_warnw2x("stdin contained a null character", " - using default instead") ;
-      }
-      else modif.len = reallen + 1 ;
+      val = def ;
+      strerr_warnw2x("stdin contained a null character", " - using default instead") ;
     }
-    if (chomp && (modif.s[modif.len - 2] == '\n'))
-      modif.s[--modif.len - 1] = 0 ;
   }
-  xmexec0_n(argv + 1, modif.s, modif.len, 1) ;
+  else if (chomp && (value.s[value.len - 2] == '\n'))
+    value.s[--value.len - 1] = 0 ;
+  el_modif_and_exec(argv + 1, argv[0], val, doimport) ;
 }
diff --git a/src/include/execline/execline.h b/src/include/execline/execline.h
index bbe4db9..144283d 100644
--- a/src/include/execline/execline.h
+++ b/src/include/execline/execline.h
@@ -4,6 +4,7 @@
 #define EXECLINE_H
 
 #include <sys/types.h>
+
 #include <skalibs/gccattributes.h>
 #include <skalibs/buffer.h>
 #include <skalibs/stralloc.h>
@@ -76,4 +77,10 @@ struct elsubst_s
 
 extern int el_substitute (stralloc *, char const *, size_t, char const *, char const *, elsubst_t const *, unsigned int) ;
 
+
+/* Execution with or without substitution */
+
+extern void el_modif_and_exec (char const *const *, char const *, char const *, int) gccattr_noreturn ;
+extern pid_t el_modif_and_spawn (char const *const *, char const *, char const *, int) ;
+
 #endif
diff --git a/src/libexecline/deps-lib/execline b/src/libexecline/deps-lib/execline
index 96d4e18..e896f2f 100644
--- a/src/libexecline/deps-lib/execline
+++ b/src/libexecline/deps-lib/execline
@@ -1,5 +1,7 @@
 el_execsequence.o
 el_getstrict.o
+el_modif_and_exec.o
+el_modif_and_spawn.o
 el_parse.o
 el_parse_from_buffer.o
 el_parse_from_string.o
diff --git a/src/libexecline/el_modif_and_exec.c b/src/libexecline/el_modif_and_exec.c
new file mode 100644
index 0000000..e2a3618
--- /dev/null
+++ b/src/libexecline/el_modif_and_exec.c
@@ -0,0 +1,36 @@
+/* ISC license. */
+
+#include <string.h>
+
+#include <skalibs/env.h>
+#include <skalibs/exec.h>
+
+#include <execline/config.h>
+#include <execline/execline.h>
+
+void el_modif_and_exec (char const *const *argv, char const *var, char const *value, int doimport)
+{
+  size_t varlen = strlen(var) ;
+  size_t modiflen = value ? varlen + strlen(value) + 2 : 1 ;
+  char modifs[modiflen] ;
+  if (value)
+  {
+    memcpy(modifs, var, varlen) ;
+    modifs[varlen] = '=' ;
+    memcpy(modifs + varlen + 1, value, modiflen - varlen - 1) ;
+  }
+  if (doimport)
+  {
+    size_t m = 0 ;
+    char const *newargv[env_len(argv) + 6] ;
+    newargv[m++] = EXECLINE_BINPREFIX "importas" ;
+    newargv[m++] = "-ui" ;
+    newargv[m++] = "--" ;
+    newargv[m++] = var ;
+    newargv[m++] = var ;
+    while (*argv) newargv[m++] = *argv++ ;
+    newargv[m++] = 0 ;
+    xmexec0_n(newargv, value ? modifs : var, value ? modiflen : varlen + 1, 1) ;
+  }
+  else xmexec0_n(argv, value ? modifs : var, value ? modiflen : varlen + 1, 1) ;
+}
diff --git a/src/libexecline/el_modif_and_spawn.c b/src/libexecline/el_modif_and_spawn.c
new file mode 100644
index 0000000..0070052
--- /dev/null
+++ b/src/libexecline/el_modif_and_spawn.c
@@ -0,0 +1,39 @@
+/* ISC license. */
+
+#include <string.h>
+
+#include <skalibs/posixplz.h>
+#include <skalibs/env.h>
+
+#include <execline/config.h>
+#include <execline/execline.h>
+
+pid_t el_modif_and_spawn (char const *const *argv, char const *var, char const *value, int doimport)
+{
+  size_t varlen = strlen(var) ;
+  size_t modiflen = value ? varlen + strlen(value) + 2 : 1 ;
+  size_t envlen = env_len((char const *const *)environ) ;
+  char const *newenv[envlen + 2] ;
+  char modifs[modiflen] ;
+  if (value)
+  {
+    memcpy(modifs, var, varlen) ;
+    modifs[varlen] = '=' ;
+    memcpy(modifs + varlen + 1, value, modiflen - varlen - 1) ;
+  }
+  if (!env_mergen(newenv, envlen + 2, (char const *const *)environ, envlen, value ? modifs : var, value ? modiflen : varlen + 1, 1)) return 0 ;
+  if (doimport)
+  {
+    size_t m = 0 ;
+    char const *newargv[env_len(argv) + 6] ;
+    newargv[m++] = EXECLINE_BINPREFIX "importas" ;
+    newargv[m++] = "-ui" ;
+    newargv[m++] = "--" ;
+    newargv[m++] = var ;
+    newargv[m++] = var ;
+    while (*argv) newargv[m++] = *argv++ ;
+    newargv[m++] = 0 ;
+    return el_spawn0(newargv[0], newargv, newenv) ;
+  }
+  else return el_spawn0(argv[0], argv, newenv) ;
+}
diff --git a/src/libexecline/el_spawn0.c b/src/libexecline/el_spawn0.c
index 7e10902..0cfe017 100644
--- a/src/libexecline/el_spawn0.c
+++ b/src/libexecline/el_spawn0.c
@@ -1,6 +1,7 @@
 /* ISC license. */
 
 #include <skalibs/djbunix.h>
+
 #include <execline/config.h>
 #include <execline/execline.h>