Hi, head(1) takes line count arguments in two ways. The legacy (1977) syntax is "-count" [1]. The "new" (1992) syntax is "-n count" [2]. In either case, "count" must be a positive decimal value.
Somewhere along the way, support for the legacy syntax was neutered. At present it only works as expected if -count is the first option argument to head(1), i.e. this works: $ head -20 file but this is an error: $ head -20 -25 file I'm not a fan of this. If we're going to support the legacy syntax I think it should behave like option arguments for other utilities. You should be able to specify -count multiple times. We do this for tail(1), which has a similar legacy syntax problem. The easiest way to transparently support such invocations is to use the GNU double-colon extension for getopt(3). We then rebuild the number string with asprintf(3), parse it with strtonum(3), and free the string. Before: $ jot 10 | head -5 -6 head: unknown option -- 6 usage: head [-count | -n count] [file ...] After: $ jot 10 | head -5 -6 1 2 3 4 5 6 -- ok? [1] https://svnweb.freebsd.org/csrg/usr.bin/head/head.c?revision=1026&view=markup [2] https://svnweb.freebsd.org/csrg/usr.bin/head/head.c?revision=52824&view=markup Index: head.c =================================================================== RCS file: /cvs/src/usr.bin/head/head.c,v retrieving revision 1.22 diff -u -p -r1.22 head.c --- head.c 10 Oct 2021 15:57:25 -0000 1.22 +++ head.c 10 Oct 2021 16:44:01 -0000 @@ -49,27 +49,30 @@ int main(int argc, char *argv[]) { const char *errstr; + char *str; FILE *fp; long cnt; int ch, firsttime; long linecnt = 10; - int status = 0; + int error, status = 0; if (pledge("stdio rpath", NULL) == -1) err(1, "pledge"); - /* handle obsolete -number syntax */ - if (argc > 1 && argv[1][0] == '-' && - isdigit((unsigned char)argv[1][1])) { - linecnt = strtonum(argv[1] + 1, 1, LONG_MAX, &errstr); - if (errstr != NULL) - errx(1, "count is %s: %s", errstr, argv[1] + 1); - argc--; - argv++; - } - - while ((ch = getopt(argc, argv, "n:")) != -1) { +#define OPTSTR "0::1::2::3::4::5::6::7::8::9::n:" + while ((ch = getopt(argc, argv, OPTSTR)) != -1) { switch (ch) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + error = asprintf(&str, "%c%s", + ch, (optarg == NULL) ? "" : optarg); + if (error == -1) + err(1, "asprintf"); + linecnt = strtonum(str, 1, LONG_MAX, &errstr); + if (errstr != NULL) + errx(1, "count is %s: %s", errstr, str); + free(str); + break; case 'n': linecnt = strtonum(optarg, 1, LONG_MAX, &errstr); if (errstr != NULL)