#!/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