Existe uma maneira de conseguir find
executar uma função que eu defino no shell? Por exemplo:
dosomething () {
echo "doing something with $1"
}
find . -exec dosomething {} \;
O resultado disso é:
find: dosomething: No such file or directory
Existe uma maneira de obter find
's -exec
para ver dosomething
?
$0
.find . -exec bash -c 'dosomething "$0"' {} \;
ele vai lidar com espaços (e outros caracteres estranhos) em nomes de arquivos ...export -f
funcionará apenas em algumas versões do bash. Não é posix, nem crossplatforn,/bin/sh
terá um erro com elefonte
while read
para um loop for;for item in $(find . ); do some_function "${item}"; done
A resposta de Jak acima é ótima, mas tem algumas armadilhas que são facilmente superadas:
Isso usa null como um delimitador em vez de um avanço de linha; portanto, os nomes de arquivos com avanço de linha funcionarão. Ele também usa o
-r
sinalizador que desativa a barra invertida, sem que as barras invertidas nos nomes de arquivos não funcionem. Ele também é limpoIFS
para que os espaços em branco à direita nos nomes não sejam descartados.fonte
/bin/bash
mas não funciona/bin/sh
. Que pena.Adicione aspas
{}
como mostrado abaixo:Isso corrige qualquer erro devido a caracteres especiais retornados por
find
, por exemplo, arquivos com parênteses no nome.fonte
{}
. Isso quebrará para um nome de arquivo contendo aspas duplas.touch '"; rm -rf .; echo "I deleted all you files, haha
. Opa-exec bash -c 'echo $0' '{}' \;
Observe que, ao usarbash -c
, $ 0 é o primeiro argumento, não o nome do script.Processando resultados em massa
Para aumentar a eficiência, muitas pessoas usam
xargs
para processar resultados em massa, mas é muito perigoso. Por isso, foi introduzido um método alternativofind
que executa os resultados em massa.Observe, porém, que esse método pode vir com algumas advertências, como por exemplo, um requisito no POSIX
find
para ter{}
no final do comando.find
passará muitos resultados como argumentos para uma única chamada debash
e ofor
loop-itera esses argumentos, executando a funçãodosomething
em cada um deles.A solução acima inicia argumentos em
$1
, e é por isso que existe um_
(que representa$0
).Processando resultados um por um
Da mesma forma, acho que a resposta principal aceita deve ser corrigida para ser
Isso não é apenas mais sensato, porque os argumentos devem sempre começar em
$1
, mas também o uso$0
pode levar a um comportamento inesperado se o nome do arquivo retornado porfind
tiver um significado especial para o shell.fonte
Faça com que o script se chame, passando cada item encontrado como argumento:
Quando você executa o script por si só, ele encontra o que está procurando e chama a si próprio passando cada resultado da busca como argumento. Quando o script é executado com um argumento, ele executa os comandos no argumento e sai.
fonte
find: ‘myscript.sh’: No such file or directory
se iniciado comobash myscript.sh
...Para aqueles que procuram uma função bash que execute um determinado comando em todos os arquivos no diretório atual, compilei um das respostas acima:
Observe que ele quebra com nomes de arquivos contendo espaços (veja abaixo).
Como exemplo, considere esta função:
Digamos que eu queira alterar todas as instâncias do hello para world em todos os arquivos no diretório atual. Eu faria:
Para estar seguro com qualquer símbolo nos nomes de arquivos, use:
(mas você precisa de um
find
que manipule-print0
, por exemplo, GNUfind
).fonte
Acho a maneira mais fácil a seguir, repetindo dois comandos em um único
fonte
Para referência, evito esse cenário usando:
Obtenha Saída de localização no arquivo de script atual e itere sobre a saída conforme desejar. Concordo com a resposta aceita, mas não quero expor a função fora do meu arquivo de script.
fonte
Não é possível executar uma função dessa maneira.
Para superar isso, você pode colocar sua função em um shell script e chamar isso de
find
Agora use-o em find como:
fonte
dosomething $1
=>dosomething "$1"
e iniciar o seu arquivo corretamente comfind . -exec bash dosomething.sh {} \;
Coloque a função em um arquivo separado e
find
execute-o.As funções do shell são internas ao shell em que estão definidas;
find
nunca será capaz de vê-los.fonte
Para fornecer adições e esclarecimentos a algumas das outras respostas, se você estiver usando a opção em massa para
exec
ouexecdir
(-exec command {} +
) e quiser recuperar todos os argumentos posicionais, é necessário considerar o tratamento$0
combash -c
. Mais concretamente, considere o comando abaixo, que é usadobash -c
como sugerido acima, e simplesmente reproduz os caminhos de arquivo que terminam com '.wav' em cada diretório encontrado:O manual do bash diz:
Aqui
'check $@'
está a sequência de comandos e_ {}
os argumentos após a sequência de comandos. Observe que$@
é um parâmetro posicional especial no bash que se expande para todos os parâmetros posicionais a partir de 1 . Observe também que, com a-c
opção, o primeiro argumento é atribuído ao parâmetro posicional$0
. Isso significa que, se você tentar acessar todos os parâmetros posicionais$@
, obterá apenas parâmetros iniciando$1
e subindo. Essa é a razão pela qual a resposta de Dominik possui o_
parâmetro$0
, que é um argumento fictício para preencher o parâmetro , para que todos os argumentos que desejamos estejam disponíveis mais tarde, se usarmos$@
expansão de parâmetros, por exemplo, ou o loop for, como nessa resposta.Obviamente, semelhante à resposta aceita,
bash -c 'shell_function $0 $@'
também funcionaria passando explicitamente$0
, mas novamente, você deve ter em mente que$@
não funcionará conforme o esperado.fonte
Não diretamente, não. O Find está sendo executado em um processo separado, não no seu shell.
Crie um shell script que faça o mesmo trabalho que sua função e encontre
-exec
isso.fonte
Eu evitaria usar
-exec
completamente. Por que não usarxargs
?fonte