On 1/30/25 09:57, Eric Blake wrote:

Reviving an old thread:

On Mon, Dec 11, 2023 at 08:58:56AM -0600, Eric Blake via austin-group-l at The 
Open Group wrote:
Hello Andrew, I'm forwarding your message on to the full Austin Group.

On Sun, Dec 10, 2023 at 11:37:40PM -0500, Andrew L. Moore wrote:
Hi,
I am the author of the original GNU ed and maintain an alternative (and I
might add, much more robust) version at github.com/slewsys/ed.

One thing that I'd love to see the POSIX committee explore is the exit
status of ed.  Per the standard:

EXIT STATUS

     The following exit values shall be returned:

      0.  Successful completion without any file or command errors.
      >0.  An error occurred.

The problem with this behavior is that, in interactive use, it common to
make errors, correct them and then write the corrected file.  But by exiting
with an error, even after successfully writing, this prevents ed from being
used as the editor for many utilties, which abort when the editor exits with
a non-zero error code.

In the version of GNU ed handed over to Antonio, the behavior was that after
a successful write, the error status is reset to zero.  This had no impact
on traditional scripting and merely allowed ed to be much more friendly,
e.g., for writing git commits. Unfortunately, Antonio updated GNU ed at some
point to follow POSIX, which is sub-optimal.
-AM

POSIX Issue 8 has been released since this thread was first started,
but the topic of this thread may still be worth filing a bug to get
the wording tightened in a technical corrigenda.

Among the ideas on the table (and likely to be discussed in today's
Austin Group meeting), is comparing the behavior of ed, vi, and ex, to
see if there is any common behavior among the various editors about
distinguishing between an interactive session (where it is very common
for the user to attempt all sorts of things that may create errors,
but because the session is interactive, they can then try other things
that clear the error - so it is okay for the overall exit status to be
0 despite intermediate errors) and a batch session (the editor is
invoked to run a specific script with no chance to modify that script
based on interactive reactions, so an exit status conveying whether
the script executed as expected makes sense).
ed's traditional behavior is as follows:

If a script is provided by redirecting a file (e.g., ed -s <script),
then errors are reported and cause immediate termination of the
script. In code, the "exit_on_error" flag is set when stdin is
seekable and not a tty.

If a script is provided via pipe (e.g., printf '...' | ed -s), then
errors are reported, but they do not cause termination of the script.
Although undocumented, this is expected behavior used in production.

The global commands G, g, V and v mask errors. So to run, e.g.,
substitutions that might fail, either feed the script via a pipe or
wrap the substitutions in a global command.
Defining what makes an interactive session for an editor is still fair
game, perhaps by comparison to what makes a shell session interactive.
I'm not sure off-hand without more experimenting or source-code
browsing on whether "stdin is a tty <=> declare this an interactive
session" is the right definition, or if it should be more subtle than
that ("stdin and stderr are both tty" or even something else more
complex).

It might also be worth adding that named pipes should be opened in
read-only mode, i.e., the following should work:

ed -p '*' <(echo hello)
6
*p
hello
*f
/dev/fd/63
*

This was an omission on my part in the implementation that was
originally written for FreeBSD, which is now the basis of macOS and
GNU eds.

I might also add that SIGPIPE should probably be handled gracefully.
Here's a test case that I recently provided Antonio:

#!/usr/bin/env bash
#
buf_size=$(
    {
        yes |
            timeout -s INT 1 dd bs=1  |
            sleep 1.1
    } 2>&1 |
        sed -nE -e '/^([0-9]+).*out$/s//\1/p'
        )

truncate -s "$buf_size" buf_size.tmp
truncate -s $(( ++buf_size )) buf_size_over.tmp

trap 'rm -f buf_size{,_over}.tmp' 0 1 2 15

ed -s buf_size.tmp <<EOF
w !sleep 1; exit
!echo This is reached!
EOF

ed -s buf_size_over.tmp <<EOF
w !sleep 1; exit
!echo This should be reached!
EOF


Reply via email to