Support --all-repeats in uniq(1) for compatibility with gnu coreutils.

This adds a new -D/--all-repeats option to uniq(1), which outputs each copy
of any repeated lines (as opposed to a single copy of a repeated line). You
can specify a separator option to output a blank line before or after each
group of repeated lines. This adds compatibility with the GNU coreutils
version of uniq(1).

This change also re-groups the -c, -d, -D, -u options in the usage display
and man page to indicate that they are mutally exclusive of each other. This
matches the posix/opengroup definition of uniq(1) command line args. Note
that this change does NOT actually enforce the mutual exclusion in the code,
for now, it simply documents that the arguments should be considered
exclusive with each other.

Differential Revision:	https://reviews.freebsd.org/D22262
This commit is contained in:
ian 2019-12-15 18:05:18 +00:00
parent 5b3e917aa9
commit 23ebeca83d
2 changed files with 57 additions and 11 deletions

View File

@ -31,7 +31,7 @@
.\" From: @(#)uniq.1 8.1 (Berkeley) 6/6/93
.\" $FreeBSD$
.\"
.Dd May 1, 2018
.Dd December 15, 2019
.Dt UNIQ 1
.Os
.Sh NAME
@ -39,8 +39,7 @@
.Nd report or filter out repeated lines in a file
.Sh SYNOPSIS
.Nm
.Op Fl c
.Op Fl d | Fl u
.Op Fl c | Fl d | Fl D | Fl u
.Op Fl i
.Op Fl f Ar num
.Op Fl s Ar chars
@ -75,7 +74,24 @@ The following options are available:
Precede each output line with the count of the number of times the line
occurred in the input, followed by a single space.
.It Fl d , Fl -repeated
Only output lines that are repeated in the input.
Output a single copy of each line that is repeated in the input.
.It Fl D , Fl -all-repeated Op Ar septype
Output all lines that are repeated (like
.Fl d ,
but each copy of the repeated line is written).
The optional
.Ar septype
argument controls how to separate groups of repeated lines in the output;
it must be one of the following values:
.Pp
.Bl -tag -compact -width separate
.It none
Do not separate groups of lines (this is the default).
.It prepend
Output an empty line before each group of lines.
.It separate
Output an empty line after each group of lines.
.El
.It Fl f Ar num , Fl -skip-fields Ar num
Ignore the first
.Ar num

View File

@ -65,11 +65,18 @@ static const char rcsid[] =
#include <wchar.h>
#include <wctype.h>
static int cflag, dflag, uflag, iflag;
static int Dflag, cflag, dflag, uflag, iflag;
static int numchars, numfields, repeats;
/* Dflag values */
#define DF_NONE 0
#define DF_NOSEP 1
#define DF_PRESEP 2
#define DF_POSTSEP 3
static const struct option long_opts[] =
{
{"all-repeated",optional_argument, NULL, 'D'},
{"count", no_argument, NULL, 'c'},
{"repeated", no_argument, NULL, 'd'},
{"skip-fields", required_argument, NULL, 'f'},
@ -101,9 +108,19 @@ main (int argc, char *argv[])
(void) setlocale(LC_ALL, "");
obsolete(argv);
while ((ch = getopt_long(argc, argv, "+cdif:s:u", long_opts,
while ((ch = getopt_long(argc, argv, "+D::cdif:s:u", long_opts,
NULL)) != -1)
switch (ch) {
case 'D':
if (optarg == NULL || strcasecmp(optarg, "none") == 0)
Dflag = DF_NOSEP;
else if (strcasecmp(optarg, "prepend") == 0)
Dflag = DF_PRESEP;
else if (strcasecmp(optarg, "separate") == 0)
Dflag = DF_POSTSEP;
else
usage();
break;
case 'c':
cflag = 1;
break;
@ -194,6 +211,9 @@ main (int argc, char *argv[])
if (comp) {
/* If different, print; set previous to new value. */
if (Dflag == DF_POSTSEP && repeats > 0)
fputc('\n', ofp);
if (!Dflag)
show(ofp, prevline);
p = prevline;
b1 = prevbuflen;
@ -206,11 +226,21 @@ main (int argc, char *argv[])
thisbuflen = b1;
tthis = NULL;
repeats = 0;
} else
} else {
if (Dflag) {
if (repeats == 0) {
if (Dflag == DF_PRESEP)
fputc('\n', ofp);
show(ofp, prevline);
}
show(ofp, thisline);
}
++repeats;
}
}
if (ferror(ifp))
err(1, "%s", ifn);
if (!Dflag)
show(ofp, prevline);
exit(0);
}
@ -276,7 +306,7 @@ static void
show(FILE *ofp, const char *str)
{
if ((dflag && repeats == 0) || (uflag && repeats > 0))
if ((!Dflag && dflag && repeats == 0) || (uflag && repeats > 0))
return;
if (cflag)
(void)fprintf(ofp, "%4d %s", repeats + 1, str);
@ -343,6 +373,6 @@ static void
usage(void)
{
(void)fprintf(stderr,
"usage: uniq [-c] [-d | -u] [-i] [-f fields] [-s chars] [input [output]]\n");
"usage: uniq [-c | -d | -D | -u] [-i] [-f fields] [-s chars] [input [output]]\n");
exit(1);
}