mirror of
https://git.savannah.gnu.org/git/coreutils.git
synced 2025-09-10 07:59:52 +02:00
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, but zero count 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.
This commit is contained in:
3
NEWS
3
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
|
||||
|
||||
@@ -160,6 +160,7 @@ David Luyer david_luyer@pacific.net.au
|
||||
David Madore david.madore@ens.fr
|
||||
David Malone dwmalone@cnri.dit.ie
|
||||
David Matei matei@cs.toronto.edu
|
||||
David Pinto carandraug+dev@gmail.com
|
||||
Davide Canova kc.canova@gmail.com
|
||||
Dawson Engler engler@stanford.edu
|
||||
Dean Gaudet dean-savannah@arctic.org
|
||||
|
||||
@@ -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}
|
||||
|
||||
43
src/wc.c
43
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);
|
||||
|
||||
|
||||
@@ -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 \
|
||||
|
||||
43
tests/misc/wc-total.sh
Executable file
43
tests/misc/wc-total.sh
Executable file
@@ -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
|
||||
|
||||
printf '%s\n' '2' > 2b || framework_failure_
|
||||
printf '%s\n' '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
|
||||
Reference in New Issue
Block a user