1

I use this bash command often

find ~ -type f -name \*.smt -exec grep something {} /dev/null \;

so I am trying to turn it into a simple bash script that I would invoke like this

findgrep ~ something --mtime -12 --name \*.smt

Thanks to this answer I managed to make it work like this:

if ! options=$(getopt -o abc: -l name:,blong,mtime: -- "$@")
then
    exit 1
fi

eval "set -- $options"

while [ $# -gt 0 ]

do
    case $1 in
    -t|--mtime) mtime=${2}   ; shift;;
    -n|--name|--iname) name="$2" ; shift;;

    (--) shift; break;;
    (-*) echo "$0: error - unrecognized option $1" 1>&2; exit 1;;
    (*) break;;
    esac
    shift
done

if [ $# -eq 2 ]
then
    dir="$1"
    str="$2"
elif [ $# -eq 1 ]
then
    dir="."
    str="$1"
else
    echo "Need a search string"
    exit
fi

echo "find $dir -type f -mtime $mtime -name $name -exec grep -iln \"$str\" {} /dev/null \;"
echo "find $dir -type f -mtime $mtime -name $name -exec grep -iln \"$str\" {} /dev/null \;" | bash

but the last line - echo'ing a command into bash - seems outright barbaric, but it works.

Is there a better way to do that? somehow trying to execute the find command directly gives no output, while running the one echo'ed out in bash works ok.

4
  • It should work when you run it directly, provided you properly double-quote all variable references (e.g. ... -name "$name" ... instead of just ... -name $name ...). See "When should I wrap quotes around a shell variable?" (short answer: almost always). Commented Mar 27, 2022 at 7:41
  • @GordonDavisson - thanks but no, it dies not work: replacing the line in question with find $dir -type f -mtime $mtime -name "$name" -exec grep -iln \"$str\" {} /dev/null \; fails to produce any output. Keep in mind that $name is a string with globs like "\*pl" - I'm guessing that's the reason, but I can't work around that Commented Mar 27, 2022 at 7:47
  • Remove the escapes from the quotes around $str (i.e. use ... grep -iln "$str" ... instead of ... grep -iln \"$str\" ...) -- with the escapes, those quotes are treated as part of the pattern to search for, instead of as protecting that pattern from shell interpretation. Commented Mar 27, 2022 at 7:51
  • @GordonDavisson - thanks again, but no, no change with that either. Everything works well if I hardcode the $name variable like this: find $dir -type f -iname \*pl -mtime $mtime -exec grep -in "$str" {} /dev/null \;. But that's one of the parameters I want to be able to set. Commented Mar 27, 2022 at 9:10

1 Answer 1

1
ame $name -e

It's still not quoted. Check your script with shellcheck.

find "$dir" -type f -mtype "$mtime" -name "$name" -exec grep -iln "$str" {} ';'

You might want to take a few steps back and do some research about quoting and expansions in shel, find and glob. find program expects literal glob pattern, and unquoted variable expansions undergo filename expansion, changing *.smt into the list of words representing filenames, while find wants the pattern not the result of expansions.

I can throw: man find, man 7 glob, https://www.gnu.org/software/bash/manual/html_node/Quoting.html https://mywiki.wooledge.org/BashFAQ/050 https://mywiki.wooledge.org/BashGuide/Parameters#Parameter_Expansion

Before you start deciding how to pass variable number of arguments to find, I encourage to research Bash arrays. I would do:

#!/bin/bash

fatal() {
  echo "$0: ERROR: $*" >&2
  exit 1
}

args=$(getopt -o abc: -l name:,iname:,mtime: -- "$@") || exit 1
eval "set -- $args"
findargs=()  # bash array
while (($#)); do
    case $1 in
    -t|--mtime) findargs+=(-mtime "$2"); shift; ;;
    -n|--name) findargs+=(-name "$2"); shift; ;;
     --iname) findargs+=(-iname "$2"); shift; ;;
    --) shift; break; ;;
    -*) fatal "unrecognized option $1"; ;;
    *) break; ;;
    esac
    shift
done

if (($# == 2)); then
    dir="$1"
    str="$2"
elif (($# == 1)); then
    dir="."
    str="$1"
else
    fatal "Need a search string"
fi

set -x
find "$dir" -type f "${findargs[@]}" -exec grep -iln "$str" /dev/null {} +
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.