Hello,
The ed shell escape command currently behaves incorrectly if standard
output isn't line-buffered. As an example, consider the following ed(1)
invocations:
$ cat /tmp/ed-cmd
!echo foo
!!
$ ed < /tmp/ed-cmd
foo
!
echo foo
foo
!
$ ed < /tmp/ed-cmd > /tmp/ed-out.txt
$ cat /tmp/ed-out.txt
foo
foo
!
echo foo
!
The output of the first and second invocation differs in regards to when
the modified command-string of the !! command is output. In the first
invocation, it is output before the command is executed (which is the
behavior mandated by POSIX). However, in the second invocation it is
output **after** the command was executed (which is incorrect).
This is due to the fact that in the second invocation standard output is
a file and hence not line-buffered. Unfortunately, ed(1) does currently
not flush all I/O buffers before executing the command using system(3).
As such, output of the command will be written to standard output before
any data buffered by ed itself is written.
The patch below fixes this issue by flushing all open output streams
before executing the command using system(3). Alternatively, it may also
be sufficient to only flush stdout and (maybe) stderr.
This issue was originally discovered in GNU ed where it has been fixed
since. See: https://lists.gnu.org/archive/html/bug-ed/2021-12/msg0.html
Greetings,
Sören Tempel
diff --git bin/ed/main.c bin/ed/main.c
index dc73dd92b..1e3cd8bdb 100644
--- bin/ed/main.c
+++ bin/ed/main.c
@@ -852,6 +852,7 @@ exec_command(void)
return ERR;
GET_COMMAND_SUFFIX();
if (sflags) printf("%s\n", shcmd + 1);
+ fflush(NULL); /* flush any buffered I/O */
system(shcmd + 1);
if (!scripted) printf("!\n");
break;