On 12/09/2022 17:33, Pádraig Brady wrote:
On 12/09/2022 16:28, Mike Jonkmans wrote:
On Mon, Sep 12, 2022 at 03:45:53PM +0200, Jim Meyering wrote:
On Mon, Sep 12, 2022, 14:53 Pádraig Brady <p...@draigbrady.com> wrote:
On 12/09/2022 10:20, David Pinto wrote:
On Sun, 26 Jun 2022 at 00:49, David Pinto <carandraug+...@gmail.com>
wrote:
Hi
A couple of years ago [1] someone made a feature request for a wc
option that would skip the total line when processing multiple files.
I didn't see anyone commenting against it and it is something that I'm
constantly hacking with `head -n-1`.
I've attached a patch that implements a new `--no-total` option to wc.
I believe this patch to be trivial enough that I can't claim copyright
for anything.
Best regards
David
[1] https://lists.gnu.org/archive/html/coreutils/2015-11/msg00064.html
Hi
It's been almost 3 months without any reply. I hope it's OK to bump
it again. I've just changed the subject line to make it clear there
is a patch attached.
Thanks for the bump.
This is one of those marginal ones since
there is no extra functionality provided
by bringing the logic within the utility.
The following function would achieve the desired functionality:
wc-no-total() { wc "$@" /dev/null | head -n-2; }
Since it's easy enough to achieve with a single extra processing step,
Given the above, I'd be 60:40 against adding a --no-total option.
But thinking more, the above is awkward to combine with the --files0-from
option.
So you'd need a separate invocation in that case like:
{ find files -print0; printf '%s\0' /dev/null; } |
wc --files0-from=- |
head -n2
Even though there is still no extra functionality,
the above is starting to get a bit obtuse.
If we lifted the restriction with --files0-from
to also allow file names to be specified on the command line
(and for those to be processed after stdin),
it would mean the wc-no-total() function above would be general,
and would work for all wc invocations.
Though a --no-total option is looking more appealing
given the above considerations. I.e. that the
wc-no-total() implementation isn't obvious,
and we'd have to change wc anyway to make it general.
So I'd be 55:45 for adding this option.
Good arguments. +1
I think it is nice to have.
What about only printing the total?
With 'wc --total' or 'wc -t'.
Well ` | tail -n1` will always work to get
the total count irrespective on the number
of files processed.
I suppose we could support --total={auto,never,always,only} as the interface.
I'll think about it.
The attached implements this, and operates like:
$ wc --total=only src/wc.c /dev/null
1037 3635 30277
$ wc --total=always src/wc.c
1037 3635 30277 src/wc.c
1037 3635 30277 total
$ wc --total=never src/wc.c /dev/null
1037 3635 30277 src/wc.c
0 0 0 /dev/null
$ wc --total=auto src/wc.c /dev/null
1037 3635 30277 src/wc.c
0 0 0 /dev/null
1037 3635 30277 total
cheers,
Pádraig
From 02db67380215d0b789f0854609772230776ead14 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <p...@draigbrady.com>
Date: Sun, 26 Jun 2022 00:27:06 +0100
Subject: [PATCH] wc: add --total={auto,never,always,only} option
without this option, control of when the total is output
is quite awkward. Consider trying to suppress the total line,
which could be achieved with something like:
wc-no-total() { wc "$@" /dev/null | head -n-2; }
As well as being non obvious, it's also non general.
It would give a non failure zero could if passed a file on stdin.
Also it doesn't work in conjunction with the --files0-from option,
which would need to be handled differently with something like:
{ find files -print0; printf '%s\0' /dev/null; } |
wc --files0-from=- |
head -n2
Also getting just the total can be awkward as file names
are only suppressed when processing stdin, and
also a total line is only printed if processing more than one file.
For completness this might be achieved currently with:
wc-only-total() {
wc "$@" |
tail -n1 |
sed 's/^ *//; s/ [^ 0-9]*$//'
}
* src/wc.c: Add new --total option.
* tests/misc/wc-total.sh: New test suite for the new option.
* tests/local.mk: Reference the new test.
* doc/coreutils.texi (wc invocation): Document the new option.
* THANKS.in: Add suggestor.
* NEWS: Mention the new feature.
---
NEWS | 3 +++
THANKS.in | 1 +
doc/coreutils.texi | 33 ++++++++++++++++++++++++++++----
src/wc.c | 43 ++++++++++++++++++++++++++++++++++++++----
tests/local.mk | 1 +
tests/misc/wc-total.sh | 43 ++++++++++++++++++++++++++++++++++++++++++
6 files changed, 116 insertions(+), 8 deletions(-)
create mode 100755 tests/misc/wc-total.sh
diff --git a/NEWS b/NEWS
index d1c400e67..561587a77 100644
--- a/NEWS
+++ b/NEWS
@@ -55,6 +55,9 @@ GNU coreutils NEWS -*- outline -*-
ls now supports the --time=modification option, to explicitly
select the default mtime timestamp for display and sorting.
+ wc now accepts the --total={auto,never,always,only} option
+ to give explicit control over when the total is output.
+
** Improvements
date --debug now diagnoses if multiple --date or --set options are
diff --git a/THANKS.in b/THANKS.in
index b3827a22c..a3d179a55 100644
--- a/THANKS.in
+++ b/THANKS.in
@@ -160,6 +160,7 @@ David Luyer david_lu...@pacific.net.au
David Madore david.mad...@ens.fr
David Malone dwmal...@cnri.dit.ie
David Matei ma...@cs.toronto.edu
+David Pinto carandraug+...@gmail.com
Davide Canova kc.can...@gmail.com
Dawson Engler eng...@stanford.edu
Dean Gaudet dean-savan...@arctic.org
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index f4be26b44..699948a8b 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -3769,10 +3769,12 @@ wc [@var{option}]@dots{} [@var{file}]@dots{}
@cindex total counts
@command{wc} prints one line of counts for each file, and if the file was
-given as an argument, it prints the file name following the counts. If
-more than one @var{file} is given, @command{wc} prints a final line
-containing the cumulative counts, with the file name @file{total}. The
-counts are printed in this order: newlines, words, characters, bytes,
+given as an argument, it prints the file name following the counts. By default
+if more than one @var{file} is given, @command{wc} prints a final line
+containing the cumulative counts, with the file name @file{total}.
+This @samp{total} line can be controlled with the @option{--total} option,
+which is a GNU extension.
+The counts are printed in this order: newlines, words, characters, bytes,
maximum line length.
Each count is printed right-justified in a field with at least one
space between fields so that the numbers and file names normally line
@@ -3839,6 +3841,29 @@ Tabs are set at every 8th column.
Display widths of wide characters are considered.
Non-printable characters are given 0 width.
+@item --total=@var{when}
+@opindex --total=@var{when}
+Control when and how the final line with cumulative counts is printed.
+@var{when} is one of:
+@itemize @bullet
+@item auto
+@vindex auto @r{total option}
+- This is the default mode of @command{wc} when no @option{--total}
+option is specified. Output a total line if more than one @var{file}
+is specified.
+@item always
+@vindex always @r{total option}
+- Always output a total line, irrespective of the number of files processed.
+@item only
+@vindex only @r{total option}
+- Only output total counts. I.e., don't print individual file counts,
+suppress any leading spaces, and don't print the @samp{total} word itself,
+to simplify subsequent processing.
+@item never
+@vindex none @r{total option}
+- Never output a total line.
+@end itemize
+
@macro filesZeroFromOption{cmd,withTotalOption,subListOutput}
@item --files0-from=@var{file}
@opindex --files0-from=@var{file}
diff --git a/src/wc.c b/src/wc.c
index dee8233a6..bc52a8c0e 100644
--- a/src/wc.c
+++ b/src/wc.c
@@ -27,6 +27,7 @@
#include <wctype.h>
#include "system.h"
+#include "argmatch.h"
#include "argv-iter.h"
#include "die.h"
#include "error.h"
@@ -112,6 +113,7 @@ enum
{
DEBUG_PROGRAM_OPTION = CHAR_MAX + 1,
FILES0_FROM_OPTION,
+ TOTAL_OPTION,
};
static struct option const longopts[] =
@@ -123,11 +125,30 @@ static struct option const longopts[] =
{"debug", no_argument, NULL, DEBUG_PROGRAM_OPTION},
{"files0-from", required_argument, NULL, FILES0_FROM_OPTION},
{"max-line-length", no_argument, NULL, 'L'},
+ {"total", required_argument, NULL, TOTAL_OPTION},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
+enum total_type
+ {
+ total_auto, /* 0: default or --total=auto */
+ total_always, /* 1: --total=always */
+ total_only, /* 2: --total=only */
+ total_never /* 3: --total=never */
+ };
+static char const *const total_args[] =
+{
+ "auto", "always", "only", "never", NULL
+};
+static enum total_type const total_types[] =
+{
+ total_auto, total_always, total_only, total_never
+};
+ARGMATCH_VERIFY (total_args, total_types);
+static enum total_type total_mode = total_auto;
+
#ifdef USE_AVX2_WC_LINECOUNT
static bool
avx2_supported (void)
@@ -215,6 +236,10 @@ the following order: newline, word, character, byte, maximum line length.\n\
If F is - then read names from standard input\n\
-L, --max-line-length print the maximum display width\n\
-w, --words print the word counts\n\
+"), stdout);
+ fputs (_("\
+ --total=WHEN when to print a line with total counts;\n\
+ WHEN can be: auto, always, only, never\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
@@ -676,7 +701,8 @@ wc (int fd, char const *file_x, struct fstatus *fstatus, off_t current_pos)
if (count_chars < print_chars)
chars = bytes;
- write_counts (lines, words, chars, bytes, linelength, file_x);
+ if (total_mode != total_only)
+ write_counts (lines, words, chars, bytes, linelength, file_x);
total_lines += lines;
total_words += words;
total_chars += chars;
@@ -840,6 +866,10 @@ main (int argc, char **argv)
files_from = optarg;
break;
+ case TOTAL_OPTION:
+ total_mode = XARGMATCH ("--total", optarg, total_args, total_types);
+ break;
+
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
@@ -913,7 +943,10 @@ main (int argc, char **argv)
xalloc_die ();
fstatus = get_input_fstatus (nfiles, files);
- number_width = compute_number_width (nfiles, fstatus);
+ if (total_mode == total_only)
+ number_width = 1; /* No extra padding, since no alignment requirement. */
+ else
+ number_width = compute_number_width (nfiles, fstatus);
ok = true;
for (int i = 0; /* */; i++)
@@ -987,9 +1020,11 @@ main (int argc, char **argv)
if (read_tokens)
readtokens0_free (&tok);
- if (1 < argv_iter_n_args (ai))
+ if (total_mode != total_never
+ && (total_mode != total_auto || 1 < argv_iter_n_args (ai)))
write_counts (total_lines, total_words, total_chars, total_bytes,
- max_line_length, _("total"));
+ max_line_length,
+ total_mode != total_only ? _("total") : NULL);
argv_iter_free (ai);
diff --git a/tests/local.mk b/tests/local.mk
index 0496c2873..895797bf9 100644
--- a/tests/local.mk
+++ b/tests/local.mk
@@ -280,6 +280,7 @@ all_tests = \
tests/misc/wc-nbsp.sh \
tests/misc/wc-parallel.sh \
tests/misc/wc-proc.sh \
+ tests/misc/wc-total.sh \
tests/misc/cat-E.sh \
tests/misc/cat-proc.sh \
tests/misc/cat-buf.sh \
diff --git a/tests/misc/wc-total.sh b/tests/misc/wc-total.sh
new file mode 100755
index 000000000..aaaad0580
--- /dev/null
+++ b/tests/misc/wc-total.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# Show that wc's --total option works.
+
+# Copyright (C) 2022 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ wc
+
+echo 2 > 2b || framework_failure_
+echo 2 words > 2w || framework_failure_
+
+returns_ 1 wc --total 2b 2w > out || fail=1
+
+wc --total=never 2b 2w > out || fail=1
+cat <<\EOF > exp || framework_failure_
+ 1 1 2 2b
+ 1 2 8 2w
+EOF
+compare exp out || fail=1
+
+wc --total=only 2b 2w > out || fail=1
+cat <<\EOF > exp || framework_failure_
+2 3 10
+EOF
+compare exp out || fail=1
+
+wc --total=always 2b > out || fail=1
+test "$(wc -l < out)" = 2 || fail=1
+
+Exit $fail
--
2.26.2