If an optional numeric argument N is passed to -O / --to-stdout, only extract the N'th file that would be sent to stdout, not counting files that are excluded (e.g. with --exclude), directories etc.
Signed-off-by: Alex Bligh <a...@alex.org.uk> --- doc/tar.texi | 21 ++++++++++++++------- src/common.h | 2 ++ src/extract.c | 4 ++++ src/tar.c | 14 ++++++++++++-- 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/doc/tar.texi b/doc/tar.texi index 5df61b1..1a529cd 100644 --- a/doc/tar.texi +++ b/doc/tar.texi @@ -3349,11 +3349,12 @@ During extraction @command{tar} will pipe extracted files to the standard input of @var{command}. @xref{Writing to an External Program}. @opsummary{to-stdout} -@item --to-stdout -@itemx -O +@item --to-stdout[=@var{number}] +@itemx -O[@var{number}] During extraction, @command{tar} will extract files to stdout rather -than to the file system. @xref{Writing to Standard Output}. +than to the file system, or (if @var{number} is supplied) a specific +file. @xref{Writing to Standard Output}. @opsummary{totals} @item --totals[=@var{signo}] @@ -5483,16 +5484,22 @@ conjunction with @option{--extract} (@option{--get}, @option{-x}). This option extracting files to send them through a pipe, and do not need to preserve them in the file system. If you extract multiple members, they appear on standard output concatenated, in the order they are -found in the archive. +found in the archive, or a specific file if a numeric parameter +is passed. @table @option @opindex to-stdout -@item --to-stdout -@itemx -O +@item --to-stdout[=@var{number}] +@itemx -O[@var{number}] Writes files to the standard output. Use only in conjunction with @option{--extract} (@option{--get}, @option{-x}). When this option is used, instead of creating the files specified, @command{tar} writes -the contents of the files extracted to its standard output. This may +the concatenated contents of the files extracted to its standard output. +If @var{number} is specified, instead of concatenating, only the +file with index @var{number} that would have been sent is used; in +calculating the index, directories, excluded files and other files +that would not have been extracted are ignored. Thus @option{--to-stdout=1} +will always extract the first file that @option{--to-stdout} would concatenate. @option{--to-stdout} may be useful if you are only extracting the files in order to send them through a pipe. This option is meaningless with @option{--list} (@option{-t}). diff --git a/src/common.h b/src/common.h index 9ac22b8..1753a3d 100644 --- a/src/common.h +++ b/src/common.h @@ -281,6 +281,8 @@ GLOBAL tarlong tape_length_option; GLOBAL bool to_stdout_option; +GLOBAL uintmax_t to_stdout_index_option; + GLOBAL bool totals_option; GLOBAL bool touch_option; diff --git a/src/extract.c b/src/extract.c index 319aaa8..b6f1fa3 100644 --- a/src/extract.c +++ b/src/extract.c @@ -1439,6 +1439,7 @@ static int prepare_to_extract (char const *file_name, int typeflag, tar_extractor_t *fun) { int rc = 1; + static uintmax_t extract_index = 0; if (EXTRACT_OVER_PIPE) rc = 0; @@ -1529,6 +1530,9 @@ prepare_to_extract (char const *file_name, int typeflag, tar_extractor_t *fun) if (rc == 0) return 0; + if (to_stdout_index_option && (to_stdout_index_option != ++extract_index)) + return 0; + switch (old_files_option) { case UNLINK_FIRST_OLD_FILES: diff --git a/src/tar.c b/src/tar.c index 9111433..6fd5bb1 100644 --- a/src/tar.c +++ b/src/tar.c @@ -490,8 +490,9 @@ static struct argp_option options[] = { {NULL, 0, NULL, 0, N_("Select output stream:"), GRID }, - {"to-stdout", 'O', 0, 0, - N_("extract files to standard output"), GRID+1 }, + {"to-stdout", 'O', N_("NUMBER"), OPTION_ARG_OPTIONAL, + N_("extract files to standard output, or if NUMBER specified," + " the file with index number NUMBER"), GRID+1 }, {"to-command", TO_COMMAND_OPTION, N_("COMMAND"), 0, N_("pipe extracted files to another program"), GRID+1 }, {"ignore-command-error", IGNORE_COMMAND_ERROR_OPTION, 0, 0, @@ -1680,6 +1681,15 @@ parse_opt (int key, char *arg, struct argp_state *state) case 'O': to_stdout_option = true; + if (arg) + { + uintmax_t u; + if (xstrtoumax (arg, 0, 10, &u, "") == LONGINT_OK) + to_stdout_index_option = u; + else + FATAL_ERROR ((0, 0, "%s: %s", quotearg_colon (arg), + _("Invalid number"))); + } break; case 'p': -- 1.7.9.5