Search for man pages which contain ALL of the words 'foo' 'bar' and 'baz'
I implemented a script that does exactly this.
if [ $# -eq 0 ]; then
PATTERNS=(NAME AUTHOR EXAMPLES FILES)
else
PATTERNS=( "$@" )
fi
[ ${#PATTERNS[@]} -lt 1 ] && echo "Needs at least 1 pattern to search for" && exit 1
for i in $(find /usr/share/man/ -type f); do
TMPOUT=$(zgrep -l "${PATTERNS[0]}" "$i")
[ -z "$TMPOUT" ] && continue
for c in `seq 1 $((${#PATTERNS[@]}-1))`; do
TMPOUT=$(echo "$TMPOUT" | xargs zgrep -l "${PATTERNS[$c]}")
[ -z "$TMPOUT" ] && break
done
if [ ! -z "$TMPOUT" ]; then
#echo "$TMPOUT" # Prints the whole path
MANNAME="$(basename "$TMPOUT")"
man "${MANNAME%%.*}"
fi
done
Guess it was a waste of time :(
Edit: Seems like
man -K expr1 expr2 expr3
didn't work?
Edit: You can pass the scripts now your search terms via ./script foo bar
A few thoughts on scripting this:
Using
manpath
to get the location(s) of the man pages. If I add/home/graeme/.cabal/bin
to myPATH
,manpath
(andman
) will find man pages in/home/graeme/.cabal/share/man
.Use man itself to decompress and format the pages before searching, this way you are just searching the man text itself and not any comments etc in the raw file. Using
man
will potentially deal with multiple formats.Saving the formatted pages in a tempfile will avoid multiple decompressions and should speed things up significantly.
Here goes (with bash
and GNU find):
#!/bin/bash
set -f; IFS=:
trap 'rm -f "$temp"' EXIT
temp=$(mktemp --tmpdir search_man.XXXXXXXXXX)
while IFS= read -rd '' file; do
man "$file" >"$temp" 2>/dev/null
unset fail
for arg; do
if ! grep -Fq -- "$arg" "$temp"; then
fail=true
break
fi
done
if [ -z "$fail" ]; then
file=${file##*/}
printf '%s\n' "${file%.gz}"
fi
done < <(find $(manpath) -type d ! -name 'man*' -prune -o -type f -print0)
Not as complete as @polym's answer, but I was going to suggest something like
while IFS= read -rd $'\0' f; do
zgrep -qwm1 'foo' "$f" && \
zgrep -qwm1 'bar' "$f" && \
zgrep -qwm1 'baz' "$f" && \
printf '%s\n' "$f"
done < <(find /usr/share/man -name '*.gz' -print0)
Note that I added a -w
(word match) switch to the greps
- which may not be what you want (do you want to include matches like foolish and nutbar?)