On 03/18/2016 01:24 PM, Jim Meyering wrote:
You are welcome to push that with changes like the following:
OK, thanks, I pushed the attached patch, which contains those changes,
plus one more change: check for errors when writing to the temporary
pattern file. Marking this as done.
From f359e34a1e968ceb94980286a8ea079be21b3b56 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@cs.ucla.edu>
Date: Fri, 18 Mar 2016 15:20:53 -0700
Subject: [PATCH] zgrep: with -f SPECIAL, read SPECIAL just once
Problem reported by Fulvio Scapin in: http://bugs.gnu.org/22945
* NEWS: Document this.
* tests/zgrep-f: Add a test.
Adjust a test to cover the case of more than one line in -f's input.
* zgrep.in (with_filename): With -f FILE, if FILE is stdin or not
a regular file, copy it into a temporary and use the temporary.
---
NEWS | 4 ++++
tests/zgrep-f | 12 ++++++++++--
zgrep.in | 45 ++++++++++++++++++++++++++++++++++++++-------
3 files changed, 52 insertions(+), 9 deletions(-)
diff --git a/NEWS b/NEWS
index 6363d71..d60d5cc 100644
--- a/NEWS
+++ b/NEWS
@@ -35,6 +35,10 @@ GNU gzip NEWS -*- outline -*-
gzip -k -v no longer reports that files are replaced.
[bug present since the beginning]
+ zgrep -f A B C no longer reads A more than once if A is not a regular file.
+ This better supports invocations like 'zgrep -f <(COMMAND) B C' in Bash.
+ [bug introduced in gzip-1.2]
+
* Noteworthy changes in release 1.6 (2013-06-09) [stable]
diff --git a/tests/zgrep-f b/tests/zgrep-f
index a8eb746..1ce8cc2 100755
--- a/tests/zgrep-f
+++ b/tests/zgrep-f
@@ -20,8 +20,8 @@
. "${srcdir=.}/init.sh"; path_prepend_ ..
-echo needle > n || framework_failure_
-echo needle > haystack || framework_failure_
+printf 'needle\nn2\n' > n || framework_failure_
+cp n haystack || framework_failure_
gzip haystack || framework_failure_
fail=0
@@ -29,6 +29,14 @@ zgrep -f - haystack.gz < n > out 2>&1 || fail=1
compare out n || fail=1
+if ${BASH_VERSION+:} false; then
+ set +o posix
+ # This failed with gzip 1.6.
+ cat n n >nn || framework_failure_
+ eval 'zgrep -h -f <(cat n) haystack.gz haystack.gz' >out || fail=1
+ compare out nn || fail=1
+fi
+
# This failed with gzip 1.4.
echo a-b | zgrep -e - > /dev/null || fail=1
diff --git a/zgrep.in b/zgrep.in
index c24be57..99ace59 100644
--- a/zgrep.in
+++ b/zgrep.in
@@ -55,6 +55,7 @@ files_with_matches=0
files_without_matches=0
no_filename=0
with_filename=0
+pattmp=
while test $# -ne 0; do
option=$1
@@ -113,13 +114,34 @@ while test $# -ne 0; do
# The pattern is coming from a file rather than the command-line.
# If the file is actually stdin then we need to do a little
# magic, since we use stdin to pass the gzip output to grep.
- # Turn the -f option into an -e option by copying the file's
- # contents into OPTARG.
- case $optarg in
- (" '-'" | " '/dev/stdin'" | " '/dev/fd/0'")
- option=-e
- optarg=" '"$(sed "$escape") || exit 2;;
- esac
+ # Similarly if it is not a regular file, since it might be read repeatedly.
+ # In either of these two cases, copy the pattern into a temporary file,
+ # and use that file instead. The pattern might contain null bytes,
+ # so we cannot simply switch to -e here.
+ if case $optarg in
+ (" '-'" | " '/dev/stdin'" | " '/dev/fd/0'")
+ :;;
+ (*)
+ eval "test ! -f$optarg";;
+ esac
+ then
+ if test -n "$pattmp"; then
+ eval "cat --$optarg" >>"$pattmp" || exit 2
+ continue
+ fi
+ trap '
+ test -n "$pattmp" && rm -f "$pattmp"
+ (exit 2); exit 2
+ ' HUP INT PIPE TERM 0
+ if type mktemp >/dev/null 2>&1; then
+ pattmp=$(mktemp -t -- "zgrep.XXXXXX") || exit 2
+ else
+ set -C
+ pattmp=${TMPDIR-/tmp}/zgrep.$$
+ fi
+ eval "cat --$optarg" >"$pattmp" || exit 2
+ optarg=' "$pattmp"'
+ fi
have_pat=1;;
(--h | --he | --hel | --help)
echo "$usage" || exit 2
@@ -232,5 +254,14 @@ do
test 126 -le $res && break
done
+if test -n "$pattmp"; then
+ rm -f "$pattmp" || {
+ r=$?
+ test $r -lt 2 && r=2
+ test $res -lt $r && res=$r
+ }
+ trap - HUP INT PIPE TERM 0
+fi
+
test 128 -le $res && kill -$(expr $res % 128) $$
exit $res
--
2.5.0