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