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.

simone
  • 4,667
  • 4
  • 25
  • 47
  • 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?"](https://stackoverflow.com/questions/10067266/when-should-i-wrap-quotes-around-a-shell-variable) (short answer: almost always). – Gordon Davisson Mar 27 '22 at 07: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 – simone Mar 27 '22 at 07: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. – Gordon Davisson Mar 27 '22 at 07: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. – simone Mar 27 '22 at 09:10

1 Answers1

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 {} +
KamilCuk
  • 120,984
  • 8
  • 59
  • 111