Skip to content

Add e command (execute) #476

Description

@dspinellis

Bug

The GNU e command — execute a shell command and send its output to the
pattern space or output stream — is not implemented. This is the standalone
command counterpart to the s///e substitute flag.

Reproduction

$ echo a | /usr/bin/sed 'e echo hi'
hi
a

$ echo a | ./target/release/sed 'e echo hi'
sed: <script argument 1>:1:1: error: invalid command code `e'

Pattern-space execution form:

$ echo 'echo hi' | /usr/bin/sed 'e'
hi

$ echo 'echo hi' |  ./target/release/sed 'e'
sed: <script argument 1>:1:1: error: invalid command code `e'

Remember that, following the GNU documentation, the pattern space is only replaced with the bare e command.

$ echo a | /usr/bin/sed -e 'e echo hi' -e 's/hi/ho/'
hi
a
$ echo 'echo hi' | /usr/bin/sed -e e -e 's/hi/ho/'
ho

Regarding implementation, for e with arguments, rather than reading the shell command's input,
it's probably more efficient and desirable to flush the sed output and simply have the shell's output appear on the standard output.
Given the cost of invoking a shell, the cost of the flush is negligible, and, if the invoked command's output is large, the savings in CPU instructions and memory will be substantial.

Note however, that this is not how GNU sed works (notice the two write system calls):

$ echo a | strace -fe write /usr/bin/sed -e 'e echo hi' -e 's/hi/ho/' >/dev/null
strace: Process 3630943 attached
[pid 3630943] write(1, "hi\n", 3)       = 3
[pid 3630943] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=3630943, si_uid=1001, si_status=0, si_utime=0, si_stime=0} ---
write(1, "hi\na\n", 5)                  = 5
+++ exited with 0 +++

What it should do

GNU sed manual:

e [COMMAND] This command allows one to pipe input from a shell command
into pattern space. Without parameters, the e command executes the command
that is found in pattern space and replaces the pattern space with the output;
a trailing newline is suppressed.

Behavior notes:

  • With an argument, execute that argument as a shell command and (this is the default) have stdout
    appear on the output stream.

  • Without an argument, execute the current pattern space as a shell command,
    replace pattern space with stdout, and suppress one trailing newline.

  • Accepts addresses like other commands.

  • Must be rejected under --sandbox.

  • Must be rejected under --posix.

Suspected place to add it

src/sed/compiler.rs — get_cmd_spec. Add an e entry with a handler
that parses the rest of the line as an optional shell command:

'e' => Ok(CommandSpec {
n_addr: 2,
handler: compile_execute_command,
}),

The execution side belongs in src/sed/processor.rs: spawn a shell
(/bin/sh -c on Unix), collect stdout, and either write it to
stdout for e COMMAND or replace pattern space for bare e.
Arrange to reuse the functionality added in b14272c.

Security note

The standalone e command is one of the commands disabled by --sandbox
along with r/w and s///e. Enforce this at compile time so the script
is rejected before any input is read.

Affected GNU testsuite tests

eval, sandbox.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions