Files
exercism/bash/grep/grep.sh
2021-08-08 21:11:22 +02:00

89 lines
2.3 KiB
Bash
Executable File

#!/usr/bin/env bash
usage () {
echo "usage: grep.sh [-nlivx] [-e] pattern file [...]"
exit 1
}
# no arguments
LN= # be sure variables are reset
FN=
RV=
FL=
MULTI=
# parse args:
while getopts ":nlivxe" arg; do
case $arg in
n) LN=t ;; # will print line number
l) FN=t ;; # only file names
i) shopt -s nocasematch ;; # case insensitive
v) RV=t ;; # reverse search
x) FL=t ;; # full line search
e) break ;; # not in exercise: end args
*) usage ;;
esac
done
shift $((OPTIND-1))
# need at least pattern and 1 file.
# TODO: consider stdin if no file
[[ $# < 2 ]] && usage
[[ $# > 2 ]] && MULTI=t
# full line match
if [[ $FL = t ]]; then
pattern="^$1\$"
else
pattern=".*$1.*"
fi
shift
# will prevent leading/trailing whitespaces to be trimmed
IFS=""
while [[ $# > 0 ]]; do
file="$1"
if [[ ! -r "$file" ]]; then
echo "$file: no such file, or not readable."
exit 1
fi
lnum=0 # line number
match=n
while read -r line ; do # will consider '\' as normal char
(( lnum ++ ))
if [[ $line =~ $pattern ]] ; then # line match
match=y
# print only filename, go to next file
[[ $FN = t ]] && echo "$file" && break
# not reverse matching only
if [[ $RV != t ]]; then
# multiple files: print filename
[[ $MULTI == t ]] && echo -n "$file:"
[[ $LN = t ]] && echo -n "$lnum:"
echo "$line"
fi
else
# reverse match
if [[ $RV == t ]]; then
# print only filename, go to next file
[[ $FN = t ]] && echo "$file" && break
# multiple files: print filename
[[ $MULTI == t ]] && echo -n "$file:"
[[ $LN = t ]] && echo -n "$lnum:"
echo "$line"
fi
fi
done < "$1"
shift # next file
done
exit 0