find -exec não funciona no script bash mas funciona no terminal [duplicado]

1

Eu estou tentando escrever um script bash para substituir um comando que eu geralmente uso. Aqui está o código do meu arquivo test.sh

#!/bin/bash
echo -e "\n"

i=0
args[i++]=$0
for arg in $@ ; do
  args[i++]=$arg
done

where="."
what="-type f"
gcase=
str=

while getopts "d:f:F:ih" opt ; do
  case $opt in
    h)
      echo -e "This is the help of this search function."
      echo -e "\t $0 [-d <dir>] [-f|-F <pattern>] [-i] string"
      echo -e "This will output the result of"
      echo -e "\t find dir -[i]name pattern -exec grep --color -Hn[i] string {} \;"
      echo -e "Default is"
      echo -e "\t find . -type f -exec grep --color -Hn string {} \;\n"
      exit 0
      ;;
    d)
      OPTIND=$(($OPTIND-1))
      where=
      tmp=${args[$OPTIND]}
      while [[ $OPTIND -lt $# ]] && [[ "${tmp:0:1}" != "-" ]] ; do
        where="$where"" $tmp"
        OPTIND=$(($OPTIND+1))
        tmp=${args[$OPTIND]}
      done
      ;;
    F)
      what="-iname "
      what="$what""\"$OPTARG\""
      ;;
    f)
      what="-name "
      what="$what""\"$OPTARG\""
      ;;
    i)
      gcase="-i"
      ;;
    \?)
      echo "Invalide option, use option -h for help." >&2
      exit 0
      ;;
  esac
done

str=${args[$OPTIND]}

command="find $where $what -exec grep --color -Hn $gcase \"$str\" {} \;"
echo "$command"
$command

Agora, no meu terminal, eu faço ./test.sh -d auto-avoid -F "TEST*" "main" e recebo

find  auto-avoid -iname "TEST*" -exec grep --color -Hn  "main" {} \;
find: missing argument to '-exec'

( auto-avoid é um diretório com um pequeno programa c ++ que escrevi por diversão.)

Então, no meu terminal eu copio e colo o comando find auto-avoid -iname "TEST*" -exec grep --color -Hn "main" {} \; e recebo

auto-avoid/test.cpp:26:int main(int argc, char **argv)

qual é o resultado esperado.

A pergunta é: o que eu senti falta?

Por enquanto eu escrevi como um script independente para testá-lo, mas o objetivo é tê-lo como uma função no meu .bash_aliases .

Eu encontrei algum tópico semelhante, mas nada que pudesse me ajudar. Se você achar que esta é uma pergunta duplicada, terei prazer em aceitar a solução.

Tenho certeza que algumas pessoas me telefonarão para usar grep -r , mas pelo menos eu gostaria de entender por que meu script não funciona. Este é um exemplo mínimo de "não", vou excluir algum diretório do meu find depois.     
por Tsathoggua 08.02.2017 / 15:31

1 resposta

4

Use set -x para ver o que o shell realmente tenta para executar:

$ command='find foo -iname "TEST*" -exec grep --color -F -Hn "main" {} \;'
$ echo "$command"
find foo -iname TEST* -exec grep --color -F -Hn main {} \;
$ set -x
$ $command
+ find foo -iname 'TEST*' -exec grep --color -F -Hn main '{}' '\;'
find: missing argument to '-exec'

Observe o '\;' : você está dando find uma barra invertida literal, o que não é o que ele espera.

As aspas duplas cumprem a mesma função que a barra invertida, escapando do ponto-e-vírgula para que seja tomada como um caractere, e não como um separador de comando.

Estes devem ser equivalentes:

$ foo="something ;"
$ foo=something\ \;

Além disso, observe que executar uma linha de comando com $command é um pouco complicado: se você tiver espaços em algum dos argumentos que vão para o comando resultante (por exemplo, no nome do caminho que você possui em $where ), eles Dividido. As matrizes da Shell oferecem uma maneira mais robusta de fazer isso.

    
por 08.02.2017 / 15:42