One way with GNU find
or compatible (-iname
is already a GNU extension anyway) could be to define the function as:
findn() (
if [ -t 1 ]; then # if the output goes to a terminal
action=-print # simple print for the user to see
else
action=-print0 # NUL-delimited records so the output can be post-processed
fi
first=true
for arg do
if "$first"; then
set -- "$@" '('
first=false
else
set -- "$@" -o
fi
set -- "$@" -iname "*$arg*"
shift
done
"$first" || set -- "$@" ')'
exec find . "$@" "$action"
)
Then you can use it as:
findn foo bar
To see the file names that contain foo
or bar
(change the -o
to -a
above if you want instead the ones that contain both foo
and bar
).
And:
findn foo bar | xargs -r0 cat
If you want to apply a command on each file found by findn
.
For a variant that does both and and not:
findn() (
if [ -t 1 ]; then # if the output goes to a terminal
action=-print # simple print for the user to see
else
action=-print0 # NUL-delimited records so the output can be post-processed
fi
first=true
for arg do
if "$first"; then
set -- "$@" '('
first=false
else
set -- "$@"
fi
if [ "$arg" = ! ]; then
set -- "$@" !
else
case $arg in
(*[][*?\\]*)
# already contains wildcard characters, don't wrap in *
set -- "$@" -iname "$arg"
;;
(*)
set -- "$@" -iname "*$arg*"
;;
esac
fi
shift
done
"$first" || set -- "$@" ')'
exec find . "$@" "$action"
)
And then:
findn foo bar ! baz
For the filenames that contain both foo
and bar
and not baz
.
In that variant, I also made it so that if the argument contained a wildcard character, it was taken as-is, so you can do:
findn foo ! 'bar*'
To look for files that do not start with bar. If you're using the zsh
shell, you can make an alias:
alias findn='noglob findn'
To disable globbing on that command which allows you to write:
find foo ! bar*
You may want to make that a script (here a sh
script is enough as that syntax is POSIX) instead of a function, so it can be called from anywhere instead of just your shell.