You really need to use arrays to keep track of strings that are separate. Using a single string to hold multiple values makes it impossible to use the code with suffixes that have the delimiter embedded (for example the suffix ,v
, which CVS and RCS files have).
exclude=( .el .htm )
include=( .texi .org )
opts=( -h -i -r )
for ext in "${exclude[@]}"; do
opts+=( --exclude="$ext" )
done
for ext in "${include[@]}"; do
opts+=( --include="$ext" )
done
grep "${opts[@]}" "$@"
This stores your filename suffixes in two arrays, exclude
and include
. It then iterates over the elements of both arrays, adding the appropriate options to a third array called opts
. This third array is then used in the call to grep
.
The double quoting used when expanding an array, as in e.g. "${opts[@]}"
, ensures that each individual array element is double quoted and not further split or globbed by the shell.
As a function that takes the lists of included and excluded filename suffixes as two separate arguments:
call_grep () {
local -n include="$1"
local -n exclude="$2"
shift 2
local opts=( -h -i -r )
local ext
for ext in "${exclude[@]}"; do
opts+=( --exclude="*$ext" )
done
for ext in "${include[@]}"; do
opts+=( --include="*$ext" )
done
grep "${opts[@]}" "$@"
}
The main part of the script:
excl=( .el .htm )
incl=( .texi .org )
call_grep incl excl more arguments here
This sets up the function call_grep
to take the names of two arrays. The first array is the array of filename suffixes to include and the second one is the array of suffixes to exclude. The function receives the names of these arrays and uses them to set up two local name-reference variables.
The third argument onwards are passed to grep
as is.
Again, but using real command line parsing in call_grep
:
call_grep () {
OPTIND=1
local ext opt
local opts=( -h -i -r )
while getopts 'i:e:' opt; do
case $opt in
i)
local -n include="$OPTARG"
for ext in "${include[@]}"; do
opts+=( --include="*$ext" )
done
;;
e)
local -n exclude="$OPTARG"
for ext in "${exclude[@]}"; do
opts+=( --exclude="*$ext" )
done
;;
*)
echo 'Error in option parsing' >&2
exit 1
esac
done
shift "$(( OPTIND - 1 ))"
grep "${opts[@]}" "$@"
}
The function now takes a -i
and a -e
argument (both are optional). The option argument to each should be the name of an array containing filename suffixes to include or exclude.
You would use this as
excl=( .el .htm )
incl=( .texi .org )
call_grep -i incl -e excl -- more arguments here
You would need to use --
to delimit the function's arguments from those that should be passed directly to grep
.
If all you want is a simplified way of calling grep
, which does not mention shell patterns or long options:
call_grep () {
OPTIND=1
while getopts 'i:e:' opt; do
case $opt in
i) opts+=( --include="*$OPTARG" ) ;;
e) opts+=( --exclude="*$OPTARG" ) ;;
*) echo 'error' >&2; exit 1
esac
done
shift "$(( OPTIND - 1 ))"
grep "${opts[@]}" "$@"
}
You'd use -i suffix
repeatedly to include multiple suffixes, and similarly for excluding suffixes. For example,
call_grep -i .texi -e .el -e .htm -i .org -- other arguments for grep here
or
call_grep -i{.texi,.org} -e{.htm,.el} -- more here for grep
excl
andincl
. To reflectexcl="el,htm"
we would then want to have--exclude=\*.{el,htm}
. – Pietru Jul 24 '21 at 12:25*.
(e.g. a filename excluded by matching*.el
would never be included by matching*.org
). – rowboat Jul 24 '21 at 14:14