Primeiro exemplo
$ ffind $intVal
'' is not a valid resource
Isso não funciona porque $foo
é a sintaxe das variáveis e você não tem uma variável chamada intVal
set, portanto $intVal
é traduzido para uma string vazia. Como a variável também é sem aspas, nenhum argumento é passado para ffind
.
Para corrigir isso, escape do $
- ou \$intVal
(barra invertida) ou '$intVal'
(citação simples).
Se você realmente tiver uma variável chamada intVal
, coloque duplo em vez disso - "$intVal"
- isso será expanda o valor da variável, mas não a dividirá.
Note que não existe tal coisa como "passar por referência" no bash. Há apenas passagem por valor e (complicado) passo a passo.
Segundo exemplo
$ ffind "testing :"
bash: [: testing: unary operator expected
'testing :' is not a valid resource
Isso não funciona porque você esqueceu de colocar aspas em torno de $1
na linha if [ $1 ]
, portanto, está sujeito a divisão de palavras e três argumentos são passados para o [
builtin:
- "
[
" - "
testing
" - "
:
" - "
]
"
em vez dos dois esperados:
- "
[
" - "
testing :
" - "
]
"
O Exemplo # 1 também é afetado por isso, pois [ $1 ]
divide em (" [
", " ]
") e não (" [
", "
", " ]
"). Exemplo # 1 funciona por acidente, no entanto, já que aparentemente [ ]
é válido. (Eu não sabia disso ...)
Para corrigir esse problema, coloque aspas duplas em torno de $1
- [ "$1" ]
.
Observação: Embora [
seja padrão, há também um operador [[
específico do bash, que na verdade tem regras de análise diferentes do resto do código - em particular, não dividir variáveis expandidas. No bash, [[ $1 ]]
e [[ "$1" ]]
são equivalentes, ao contrário de suas alternativas [
.
Mais bugs
Sua função também tem vários outros problemas que não são mostrados nos exemplos.
find -type f | grep -ir '$1' * | grep -v '.svn'
Nesta linha:
-
A palavra
'$1'
tem aspas simples ao redor. Isso significa que o bash não expandirá seu conteúdo - você está realmente dizendo grep para procurar o regex$1
, e não o argumento da linha de comando.Para corrigir isso, use aspas duplas -
"$1"
-
O primeiro comando grep está sendo solicitado para pesquisar recursivamente o conteúdo de todos os arquivos no diretório atual (
-r
e*
curinga).Ao mesmo tempo, você está canalizando a saída de
find -type f
para grep - aparentemente tentando dizer grep para pesquisar os nomes de todos os arquivos.Isso não funcionará porque grep , como a maioria dos filtros, não lerá de stdin se receber um ou mais arquivos para pesquisar. Eu não sei o que você está tentando pesquisar - nomes de arquivos ou conteúdo de arquivos - então escolha um:
-
Para procurar apenas nomes de arquivos, mantenha o pipe, mas remova a especificação do arquivo:
find -type f | grep -i "$1" | ...
-
Para pesquisar apenas o conteúdo do arquivo, remova o
find|
:grep -ir "$1" * | ...
-
É possível combinar ambos, explicitamente dando grep o arquivo "stdin":
find -type f | grep -i "$1" - * | ... find -type f | grep -i "$1" /dev/stdin * | ...
(
/dev/stdin
funciona com todos os programas Linux, enquanto-
é uma convenção usada por alguns programas, incluindo o grep.)
-
-
No segundo comando grep , a regex de pesquisa é um pouco ampla demais. (Lembre-se de que é uma regex, não uma string fixa).
.svn
corresponderia a algo como "not-a-svn-file
".Para excluir o diretório
.svn
, usegrep -v "/\.svn/"
.Se pesquisar o arquivo conteúdo (
grep -ir ...
), é melhor livrar-se do comandogrep -v
e adicionar--exclude-dir=".svn"
ao primeiro.
Você pode parar de ler neste ponto
Os itens abaixo são apenas uma boa prática nos scripts sh .
-
A palavra-chave
function
é desnecessária:ffind() { ...
é suficiente e funciona em todos os shells do POSIX (enquantofunction ffind
não seria ). -
Se um script, programa ou função falhar, ele deve retornar um status de "falha" para seu pai. Por convenção, os programas Unix consideram
0
como "sucesso" e qualquer outra coisa "falha" (embora haja exceções para o último).Para retornar um status explicitamente, use
return <num>
em uma função (ouexit <num>
em um script independente):else echo "'$1' is not a valid resource" >&2 return 1 fi
-
Da mesma forma, as mensagens de erro não devem ser misturadas com stdout normal, mas gravadas em stderr (fd # 2), usando o operador de redirecionamento
>&
(veja o exemplo acima). Dessa forma, você pode redirecionar a saída normal para um arquivo (por exemplo,ffind intVal > results.txt
) enquanto ainda apresenta erros na tela.
Código fixo
ffind()
{
if [ "$1" ] ; then
grep -ir --exclude-dir=".svn" "$1" .
else
echo "'$1' is not a valid resource" >&2
return 1
fi
}
Melhores ferramentas
ack afirma ser "melhor que o grep". A execução de ack "testing :"
pesquisaria seu código-fonte e ignoraria automaticamente .svn
e diretórios semelhantes.