commit 77f8d7e5934c146d047c6c38b97067ae046268d9
parent 5765a6e6b434ce692a15ed2e64bc2ea0d1c5a2e1
Author: Roberto E. Vargas Caballero <k0ga@shike2.net>
Date: Sat, 13 Dec 2025 12:51:11 +0100
ed: Add the x and X commands
These are extensions to the POSIX standard but very useful
in situations like writing a commit message where the exit
status can discard the full edit session.
Diffstat:
4 files changed, 62 insertions(+), 3 deletions(-)
diff --git a/ed.1 b/ed.1
@@ -216,6 +216,16 @@ instead.
.It (.+1)
An address without a command prints the addressed line.
Sets the dot to that line.
+.It (1,$)x file
+Like the w command
+but after saving the file
+it exits with an exit status of 0
+independently of previous errors.
+.It (1,$)X file
+Like the W command
+but after saving the file
+it exits with an exit status of 0
+independently of previous errors.
.It (+) Ns Ic z Ns Ar n
Scrolls
.Ar n
@@ -273,6 +283,9 @@ The dot is unchanged.
POSIX.1-2013.
Except where noted here:
g and v operate on single commands rather than lists delimited with '\e'.
-The command
-.Cm z
-is an extension to that specification.
+The command,
+.Cm z ,
+.Cm x ,
+and
+.Cm X
+are an extension to that specification.
diff --git a/ed.c b/ed.c
@@ -1431,6 +1431,15 @@ repeat:
chkprint(1);
optprompt ^= 1;
break;
+ case 'x':
+ trunc = 1;
+ case 'X':
+ ensureblank();
+ if (nlines > 0)
+ goto unexpected;
+ exstatus = 0;
+ deflines(nextln(0), lastln);
+ dowrite(getfname(cmd), trunc);
case 'Q':
case 'q':
if (nlines > 0)
diff --git a/tests/0019-ed.sh b/tests/0019-ed.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+tmp=tmp.$$
+
+trap 'rm -f $tmp' EXIT
+trap 'rm -f $tmp; kill -KILL $$' HUP INT TERM
+
+set -e
+
+../ed -s $tmp <<EOF >/dev/null
+a
+1
+2
+.
+5d
+x
+EOF
+
+printf '1\n2\n' | diff -u $tmp -
diff --git a/tests/0020-ed.sh b/tests/0020-ed.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+tmp=tmp.$$
+
+trap 'rm -f $tmp' EXIT
+trap 'rm -f $tmp; kill -KILL $$' HUP INT TERM
+
+set -e
+
+../ed -s $tmp <<EOF >/dev/null
+a
+1
+2
+.
+w
+5d
+X
+EOF
+
+printf '1\n2\n1\n2\n' | diff -u $tmp -