Preciso passar uma função como parâmetro no Bash. Por exemplo, o seguinte código:
function x() {
echo "Hello world"
}
function around() {
echo "before"
eval $1
echo "after"
}
around x
Deve produzir:
before
Hello world
after
Eu sei que eval
não está correto nesse contexto, mas isso é apenas um exemplo :)
Qualquer ideia?
function
palavra, não poderá acessar esses métodos internos até executar o método de nível superior.Acho que ninguém respondeu exatamente à pergunta. Ele não perguntou se ele poderia ecoar cordas em ordem. Em vez disso, o autor da pergunta deseja saber se ele pode simular o comportamento do ponteiro de função.
Existem algumas respostas que são muito parecidas com o que eu faria e quero expandi-las com outro exemplo.
Do autor:
function x() { echo "Hello world" } function around() { echo "before" ($1) <------ Only change echo "after" } around x
Para expandir isso, teremos a função x echo "Hello world: $ 1" para mostrar quando a execução da função realmente ocorre. Vamos passar uma string que é o nome da função "x":
function x() { echo "Hello world:$1" } function around() { echo "before" ($1 HERE) <------ Only change echo "after" } around x
Para descrever isso, a string "x" é passada para a função around () que ecoa "antes", chama a função x (através da variável $ 1, o primeiro parâmetro passado para around) passando o argumento "AQUI" e finalmente ecoa depois .
Como outro aparte, esta é a metodologia para usar variáveis como nomes de funções. As variáveis realmente contêm a string que é o nome da função e ($ variable arg1 arg2 ...) chama a função passando os argumentos. Ver abaixo:
function x(){ echo $3 $1 $2 <== just rearrange the order of passed params } Z="x" # or just Z=x ($Z 10 20 30)
dá: 30 10 20, onde executamos a função chamada "x" armazenada na variável Z e passamos os parâmetros 10 20 e 30.
Acima, onde referimos funções atribuindo nomes de variáveis às funções para que possamos usar a variável no lugar de realmente saber o nome da função (que é semelhante ao que você pode fazer em uma situação de ponteiro de função muito clássica em c para generalizar o fluxo do programa, mas antes -selecionando as chamadas de função que você fará com base nos argumentos da linha de comando).
No bash, esses não são ponteiros de função, mas variáveis que se referem a nomes de funções que você usará posteriormente.
fonte
()
não iniciará um sub-shell?não há necessidade de usar
eval
function x() { echo "Hello world" } function around() { echo "before" var=$($1) echo "after $var" } around x
fonte
Você não pode passar nada para uma função diferente de strings. As substituições de processos podem meio que falsificá-lo. O Bash tende a manter aberto o FIFO até que um comando seja expandido para ser concluído.
Aqui está um rápido e bobo
foldl() { echo $(($(</dev/stdin)$2)) } < <(tr '\n' "$1" <$3) # Sum 20 random ints from 0-999 foldl + 0 <(while ((n=RANDOM%999,x++<20)); do echo $n; done)
As funções podem ser exportadas, mas isso não é tão interessante quanto parece à primeira vista. Acho que é principalmente útil para tornar as funções de depuração acessíveis a scripts ou outros programas que executam scripts.
( id() { "$@" } export -f id exec bash -c 'echowrap() { echo "$1"; }; id echowrap hi' )
id
ainda obtém apenas uma string que é o nome de uma função (importada automaticamente de uma serialização no ambiente) e seus args.O comentário de Pumbaa80 para outra resposta também é bom (
eval $(declare -F "$1")
), mas é útil principalmente para arrays, não funções, já que eles são sempre globais. Se você executasse isso dentro de uma função, tudo o que faria seria redefini-lo, portanto, não teria efeito. Não pode ser usado para criar fechamentos ou funções parciais ou "instâncias de função" dependendo do que quer que esteja vinculado no escopo atual. Na melhor das hipóteses, isso pode ser usado para armazenar uma definição de função em uma string que é redefinida em outro lugar - mas essas funções também podem ser codificadas somente a menos queeval
seja usadoBasicamente, o Bash não pode ser usado dessa forma.
fonte
Uma abordagem melhor é usar variáveis locais em suas funções. O problema passa a ser como você entrega o resultado ao chamador. Um mecanismo é usar a substituição de comando:
function myfunc() { local myresult='some value' echo "$myresult" } result=$(myfunc) # or result=`myfunc` echo $result
Aqui, o resultado é enviado para o stdout e o chamador usa a substituição de comando para capturar o valor em uma variável. A variável pode então ser usada conforme necessário.
fonte
Você deve ter algo como:
function around() { echo 'before'; echo `$1`; echo 'after'; }
Você pode então ligar
around x
fonte
eval é provavelmente a única forma de o conseguir. A única desvantagem real é o aspecto de segurança, pois você precisa se certificar de que nada malicioso seja transmitido e apenas as funções que você deseja que sejam chamadas sejam chamadas (junto com a verificação de que não haja caracteres desagradáveis como ';' nele também).
Portanto, se você é quem está chamando o código, provavelmente eval é a única maneira de fazê-lo. Observe que existem outras formas de avaliação que provavelmente funcionariam também envolvendo subcomandos ($ () e ``), mas não são mais seguras e são mais caras.
fonte
eval $1
chamaria uma função usandoif declare -F "$1" >/dev/null; then eval $1; fi
eval $(declare -F "$1")