Hi,

This diff makes it an error to invoke sed(1) without any command or
script.

In POSIX.1-2008 the sed(1) synopsis changed from this:

  sed [-n] script[file...]
  sed [-n][-e script]...[-f script_file]...[file...]

to this:

  sed [-n] script [file...]
  sed [-n] -e script [-e script]... [-f script_file]... [file...]
  sed [-n] [-e script]... -f script_file [-f script_file]... [file]

which makes the empty invocation, i.e.

        $ sed
or

        $ ... | sed | ...

unambiguously an unrecognized form; you have to specify some sort of
script, somehow, or the behavior is undefined.

Yes, the standard was silent regarding the behavior in this case in
earlier versions, but now that the synopsis doesn't even allow for it
*and* we claim conformance to the newer standard I think we ought to
document how our implementation behaves in this case (probably note it
in STANDARDS) or drop it.  I'd like to drop it.

What do other implementations do?  FreeBSD/NetBSD/Solaris/illumos sed(1)
all (like us) descend from the Spinellis rewrite for 4.4BSD and all of
them have preserved this behavior and left it undocumented.  GNU sed and
AIX sed error out in this case.

Aside from it being undocumented, I'd like to drop this because:

  1. The empty invocation is not useful.  If you want sed to do
     nothing you can very easily do so explicitly, i.e.

        $ sed ""

     Allowing the empty invocation just makes more room for user
     error without enhancing the tool.  I appreciate that there
     *could* be a shell script out there with a variable sed script
     like this:

        ... | sed $script | ...

     where the author intended for sed(1) to go ahead and do nothing
     in certain cases and that this change would then break that script,
     but on average I imagine that this is more likely to be a "gotcha"
     than a feature.

  2. Requiring a command is consistent, usage-wise, if you think of
     sed(1) as a successor to grep(1).

     grep(1) supports matching the null pattern, i.e.

        $ grep ""

     but you have to do so explicitly.  There is no default pattern.

     Both utilities are inspired by ed(1).   grep(1) for g/re/p and sed(1)
     for all the others.

     If grep(1) fails without a pattern I think sed(1) should similarly
     fail without a command.  Just as the omission of a pattern is not
     equivalent to the null pattern, the omission of a command is not
     equivalent to the explicit instruction to do nothing, however similar
     they may appear.

--

Thoughts?  Preferences?

-Scott

Aside: I did my best here with modifying the synopsis in sed.1.  Is
there a better/preferred way to indicate that an optional flag with an
argument can be given one or more times?  That is, to produce sth like:

        [-f command_file]...

Index: POSIX
===================================================================
RCS file: /cvs/src/usr.bin/sed/POSIX,v
retrieving revision 1.2
diff -u -p -r1.2 POSIX
--- POSIX       26 Jun 1996 05:39:04 -0000      1.2
+++ POSIX       4 Dec 2018 02:47:15 -0000
@@ -128,13 +128,7 @@ All uses of "POSIX" refer to section 4.5
        does not specify this.  This implementation follows historical
        practice.
 
-14.    POSIX does not explicitly specify how sed behaves if no script is
-       specified.  Since the sed Synopsis permits this form of the command,
-       and the language in the Description section states that the input
-       is output, it seems reasonable that it behave like the cat(1)
-       command.  Historic sed implementations behave differently for "ls |
-       sed", where they produce no output, and "ls | sed -e#", where they
-       behave like cat.  This implementation behaves like cat in both cases.
+14.    Deleted.
 
 15.    The POSIX requirement to open all w files at the beginning makes
        sed behave nonintuitively when the w commands are preceded by
Index: main.c
===================================================================
RCS file: /cvs/src/usr.bin/sed/main.c,v
retrieving revision 1.38
diff -u -p -r1.38 main.c
--- main.c      14 Nov 2018 10:59:33 -0000      1.38
+++ main.c      4 Dec 2018 02:47:15 -0000
@@ -102,6 +102,7 @@ u_long linenum;
 static void add_compunit(enum e_cut, char *);
 static void add_file(char *);
 static int next_files_have_lines(void);
+static __dead void usage(void);
 
 int termwidth;
 
@@ -143,11 +144,7 @@ main(int argc, char *argv[])
                        setvbuf(stdout, NULL, _IOLBF, 0);
                        break;
                default:
-               case '?':
-                       (void)fprintf(stderr,
-                           "usage: sed [-aEnru] [-i[extension]] command [file 
...]\n"
-                           "       sed [-aEnru] [-e command] [-f command_file] 
[-i[extension]] [file ...]\n");
-                       exit(1);
+                       usage();
                }
        argc -= optind;
        argv += optind;
@@ -174,7 +171,9 @@ main(int argc, char *argv[])
        }
 
        /* First usage case; script is the first arg */
-       if (!eflag && !fflag && *argv) {
+       if (!eflag && !fflag) {
+               if (*argv == NULL)
+                       usage();
                add_compunit(CU_STRING, *argv);
                argv++;
        }
@@ -524,4 +523,16 @@ lastline(void)
        }
        ungetc(ch, infile);
        return (0);
+}
+
+static __dead void
+usage(void)
+{
+       fprintf(stderr,
+           "usage: sed [-aEnru] [-i[extension]] command [file ...]\n"
+           "       sed [-aEnru] [-e command]... [-f command_file]... 
[-i[extension]]\n"
+           "           -e command [file ...]\n"
+           "       sed [-aEnru] [-e command]... [-f command_file]... 
[-i[extension]]\n"
+           "           -f command_file [file...]\n");
+       exit(1);
 }
Index: sed.1
===================================================================
RCS file: /cvs/src/usr.bin/sed/sed.1,v
retrieving revision 1.57
diff -u -p -r1.57 sed.1
--- sed.1       14 Nov 2018 10:59:33 -0000      1.57
+++ sed.1       4 Dec 2018 02:47:15 -0000
@@ -46,9 +46,17 @@
 .Op Ar
 .Nm sed
 .Op Fl aEnru
-.Op Fl e Ar command
-.Op Fl f Ar command_file
+.Oo Fl e Ar command Oc Ns ...
+.Oo Fl f Ar command_file Oc Ns ...
 .Op Fl i Ns Op Ar extension
+.Fl e Ar command
+.Op Ar
+.Nm sed
+.Op Fl aEnru
+.Oo Fl e Ar command Oc Ns ...
+.Oo Fl f Ar command_file Oc Ns ...
+.Op Fl i Ns Op Ar extension
+.Fl f Ar command_file
 .Op Ar
 .Sh DESCRIPTION
 The

Reply via email to