With the pattern files
$ od -bc shortlong
0000000 167 150 157 012 167 150 157 163 145 012
w h o \n w h o s e \n
0000012
$ od -bc longshort
0000000 167 150 157 163 145 012 167 150 157 012
w h o s e \n w h o \n
0000012
we can test some of the variations, here with the macOS grep
(2.5.1-FreeBSD):
$ grep -x -f shortlong shortlong
who
$ grep -x -f shortlong longshort
who
$ grep -x -f longshort shortlong
who
whose
$ grep -x -f longshort longshort
whose
who
who
when first hides the longer whose
match. This appears to be
a bug.
The problem only appears when the expressions come from a -f
file, not
when the equivalent (we hope) expression is given as an argument:
$ grep -x -E 'who|whose' shortlong
who
whose
$ grep -x -E 'who|whose' longshort
whose
who
$ grep -x -E 'whose|who' shortlong
who
whose
$ grep -x -E 'whose|who' longshort
whose
who
GNU grep
(3.7) does not exhibit this problem (nor does the grep
on
current versions of OpenBSD):
$ ggrep -x -f shortlong shortlong
who
whose
$ ggrep -x -f shortlong longshort
whose
who
$ ggrep -x -f longshort shortlong
who
whose
$ ggrep -x -f longshort longshort
whose
who
Therefore to avoid this bug do not use grep
verion 2.5.1-FreeBSD, or
instead form the regular expressions into an argument from the file by
replacing non-ultimate \n
with |
for grep -E
.
$ paste -s -d \| shortlong
who|whose
$ grep -x -E -- "$(paste -s -d \| shortlong)" shortlong
who
whose
Concerning Alternation
Longer strings should ideally be listed before shorter strings in
regular expression alternations, among other edge cases, which
means one should prefer the longshort
file or whose|who
forms.
grep
appears (when it is not buggy) to get this right, but other
regular expression engines will stop on the first match, which must be
listed longest first if you want those to match:
$ printf 'who whoses the whosefolk' |
grep -o -E 'who|whose|whosefolk'
who
whose
whosefolk
$ printf 'who whoses the whosefolk' |
perl -nle 'print for /who|whose|whosefolk/g'
who
who
who
$ printf 'who whoses the whosefolk' |
perl -nle 'print for /whosefolk|whose|who/g'
who
whose
whosefolk
od
orcat -A
for examplegrep
on FreeBSD, nor with GNUgrep
. Are you sure there are no trailing spaces afterwhose
in any of the files? What Unix are you on and whatgrep
are you using?who
andwhose
witha
andb
leads to the expected result. It looks like the behavior has to do with the fact thatwho
is a substring ofwhose
, no?