Hi, I've recently found myself wishing for an option in 'wc' that shows progress during an invocation. I modified my local copy with the changes in the attached patch to accept a '--progress' option.
This patch is also available at git://repo.or.cz/coreutils/bo.git An example of behavior can be observed with the attached 'slowrite' program: $ ./slowrite 100000 | src/wc --progress 100000 200000 800000 $ src/wc --progress <(./slowrite 100000 3) <(./slowrite 1000000 4) 100000 200000 800000 /dev/fd/63 1000000 2000000 8000000 /dev/fd/62 1100000 2200000 8800000 total Of course these examples don't show any difference from an ordinary wc invocation once they're complete. ;) Here's a view when stdout isn't attached to a terminal: $ ./slowrite 100000 | src/wc --progress > log & [1] 19880 $ tail -f log 8704 17408 69632 16896 33792 135168 25088 50176 200704 33792 67584 270336 41984 83968 335872 50176 100352 401408 58368 116736 466944 67072 134144 536576 75264 150528 602112 83456 166912 667648 92160 184320 737280 100000 200000 800000 Would this be useful to anyone else? Thanks, Bo
>From 80089c8b1d616ec3c3a88b4f58131506a5aa43f3 Mon Sep 17 00:00:00 2001 From: Bo Borgerson <[EMAIL PROTECTED]> Date: Wed, 29 Oct 2008 11:00:06 -0400 Subject: [PATCH] wc: add new option, --progress * src/wc.c (set_do_monitor) ALRM handler sets DO_MONITOR flag that triggers output. (write_counts) Unset DO_MONITOR flag. New argument, is_final, set to true for the final invocation for each input. If stdout is connected to a terminal, write all counts for a single input on a single line. (wc) Check DO_MONITOR flag in read loop and call write_counts if set. (main) Set up an ALRM sigaction handler to call set_do_monitor. --- src/wc.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 78 insertions(+), 11 deletions(-) diff --git a/src/wc.c b/src/wc.c index 0bb1929..771d6f1 100644 --- a/src/wc.c +++ b/src/wc.c @@ -21,6 +21,7 @@ #include <stdio.h> #include <getopt.h> +#include <signal.h> #include <sys/types.h> #include <wchar.h> #include <wctype.h> @@ -66,6 +67,9 @@ static int number_width; /* True if we have ever read the standard input. */ static bool have_read_stdin; +/* Set by sig ALRM handler, triggers output at convenience. Unset at output. */ +static bool do_progress = false; + /* The result of calling fstat or stat on a file descriptor or file. */ struct fstatus { @@ -81,7 +85,8 @@ struct fstatus non-character as a pseudo short option, starting with CHAR_MAX + 1. */ enum { - FILES0_FROM_OPTION = CHAR_MAX + 1 + FILES0_FROM_OPTION = CHAR_MAX + 1, + PROGRESS_OPTION }; static struct option const longopts[] = @@ -92,6 +97,7 @@ static struct option const longopts[] = {"words", no_argument, NULL, 'w'}, {"files0-from", required_argument, NULL, FILES0_FROM_OPTION}, {"max-line-length", no_argument, NULL, 'L'}, + {"progress", no_argument, NULL, PROGRESS_OPTION}, {GETOPT_HELP_OPTION_DECL}, {GETOPT_VERSION_OPTION_DECL}, {NULL, 0, NULL, 0} @@ -122,6 +128,7 @@ read standard input.\n\ --files0-from=F read input from the files specified by\n\ NUL-terminated names in file F\n\ -L, --max-line-length print the length of the longest line\n\ + --progress print counts every second until complete\n\ -w, --words print the word counts\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); @@ -131,6 +138,13 @@ read standard input.\n\ exit (status); } +static void +set_do_progress (int sig) +{ + do_progress = true; + alarm (1); +} + /* FILE is the name of the file (or NULL for standard input) associated with the specified counters. */ static void @@ -139,39 +153,58 @@ write_counts (uintmax_t lines, uintmax_t chars, uintmax_t bytes, uintmax_t linelength, - const char *file) + const char *file, + bool is_final) { static char const format_sp_int[] = " %*s"; char const *format_int = format_sp_int + 1; char buf[INT_BUFSIZE_BOUND (uintmax_t)]; + static size_t plen = 0; + + if (0 < plen && isatty (STDOUT_FILENO)) + { + size_t i; + for (i = 0; i < plen; i++) + putchar (0x08); /* Backspace. */ + plen = 0; + } if (print_lines) { - printf (format_int, number_width, umaxtostr (lines, buf)); + plen += printf (format_int, number_width, umaxtostr (lines, buf)); format_int = format_sp_int; } if (print_words) { - printf (format_int, number_width, umaxtostr (words, buf)); + plen += printf (format_int, number_width, umaxtostr (words, buf)); format_int = format_sp_int; } if (print_chars) { - printf (format_int, number_width, umaxtostr (chars, buf)); + plen += printf (format_int, number_width, umaxtostr (chars, buf)); format_int = format_sp_int; } if (print_bytes) { - printf (format_int, number_width, umaxtostr (bytes, buf)); + plen += printf (format_int, number_width, umaxtostr (bytes, buf)); format_int = format_sp_int; } if (print_linelength) { - printf (format_int, number_width, umaxtostr (linelength, buf)); + plen += printf (format_int, number_width, umaxtostr (linelength, buf)); } if (file) - printf (" %s", file); - putchar ('\n'); + plen += printf (" %s", file); + + if (is_final || !isatty (STDOUT_FILENO)) + { + putchar ('\n'); + plen = 0; + } + if (!is_final) + fflush (stdout); + + do_progress = false; } /* Count words. FILE_X is the name of the file (or NULL for standard @@ -241,6 +274,10 @@ wc (int fd, char const *file_x, struct fstatus *fstatus) break; } bytes += bytes_read; + + if (do_progress) + write_counts (lines, words, chars, bytes, linelength, file_x, + false); } } } @@ -265,6 +302,9 @@ wc (int fd, char const *file_x, struct fstatus *fstatus) ++lines; } bytes += bytes_read; + + if (do_progress) + write_counts (lines, words, chars, bytes, linelength, file_x, false); } } #if HAVE_MBRTOWC && (MB_LEN_MAX > 1) @@ -401,6 +441,8 @@ wc (int fd, char const *file_x, struct fstatus *fstatus) } prev = bytes_read; # endif + if (do_progress) + write_counts (lines, words, chars, bytes, linelength, file_x, false); } if (linepos > linelength) linelength = linepos; @@ -459,6 +501,9 @@ wc (int fd, char const *file_x, struct fstatus *fstatus) } } while (--bytes_read); + + if (do_progress) + write_counts (lines, words, chars, bytes, linelength, file_x, false); } if (linepos > linelength) linelength = linepos; @@ -468,7 +513,7 @@ wc (int fd, char const *file_x, struct fstatus *fstatus) if (count_chars < print_chars) chars = bytes; - write_counts (lines, words, chars, bytes, linelength, file_x); + write_counts (lines, words, chars, bytes, linelength, file_x, true); total_lines += lines; total_words += words; total_chars += chars; @@ -623,6 +668,10 @@ main (int argc, char **argv) files_from = optarg; break; + case PROGRESS_OPTION: + do_progress = true; + break; + case_GETOPT_HELP_CHAR; case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); @@ -679,6 +728,24 @@ main (int argc, char **argv) fstatus = get_input_fstatus (nfiles, files); number_width = compute_number_width (nfiles, fstatus); + if (do_progress) + { + struct sigaction alarm_handler; + + sigemptyset (&alarm_handler.sa_mask); + + alarm_handler.sa_handler = set_do_progress; + + alarm_handler.sa_flags = SA_RESTART; + + sigaction (SIGALRM, &alarm_handler, NULL); + + alarm (1); + + /* This will be set again in one second by SET_DO_PROGRESS. */ + do_progress = false; + } + ok = true; for (i = 0; i < nfiles; i++) { @@ -720,7 +787,7 @@ main (int argc, char **argv) if (1 < nfiles) write_counts (total_lines, total_words, total_chars, total_bytes, - max_line_length, _("total")); + max_line_length, _("total"), true); free (fstatus); -- 1.5.4.3
#!/usr/bin/perl -w use strict; my ($n, $s) = @ARGV; $n or die "usage: $0 RECORDS [SECONDS]\n"; $s ||= 10; my $m = $n / 100 / $s; $m < 2 and $m = 2; for (1..$n){ print "foo bar\n"; ($_ % $m) == 1 and select (undef, undef, undef, 0.01); }
_______________________________________________ Bug-coreutils mailing list Bug-coreutils@gnu.org http://lists.gnu.org/mailman/listinfo/bug-coreutils