59 lines
1.6 KiB
Bash
59 lines
1.6 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
# parsing CLI options
|
|
while getopts :nlivx option; do
|
|
case "$option" in
|
|
# include line numbers in output
|
|
n) linenr=1 ;;
|
|
# only file names containing matching lines are printed
|
|
l) filename=1 ;;
|
|
# case insentivity
|
|
i) shopt -s nocasematch ;;
|
|
# matching lines are inverted (i.e., lines that do not match)
|
|
v) invert=1 ;;
|
|
# pattern should match whole line
|
|
x) entire=1 ;;
|
|
# other options are invalid and exit
|
|
\?) echo Invalid option.; exit 1;;
|
|
esac
|
|
done
|
|
|
|
# shifts the command-line arguments so that the remaining arguments
|
|
# are just the pattern and the files to search in
|
|
shift $((OPTIND-1))
|
|
|
|
pattern=$1
|
|
shift
|
|
files=( "$@" )
|
|
# if entire is set to 1, modifies the pattern to match the entire line
|
|
# by anchoring it with ^ (beginning of line) and $ (end of line)
|
|
(( entire )) && pattern="^$pattern$"
|
|
|
|
for file in "${files[@]}"; do
|
|
count=0
|
|
while read -r line
|
|
do
|
|
(( count++ ))
|
|
out=
|
|
if (( invert )); then
|
|
! [[ ${line} =~ ${pattern} ]] && out="$line"
|
|
else
|
|
[[ ${line} =~ ${pattern} ]] && out="$line"
|
|
fi
|
|
# if filename is set to 1, prints the file name and breaks out
|
|
# of the loop after the first matching line in each file
|
|
if (( filename )) && [[ -n $out ]]; then
|
|
echo $file;
|
|
break;
|
|
fi
|
|
if (( linenr )) && [[ -n $out ]]; then
|
|
out="$count":$out;
|
|
fi
|
|
if (( ${#files[@]} > 1 )) && [[ -n $out ]]; then
|
|
out="$file":$out;
|
|
fi
|
|
[[ -n $out ]] && echo $out;
|
|
done < "$file"
|
|
done
|
|
exit 0
|