Pergunta

Atualmente eu estou fazendo alguns testes de unidade que são executados a partir bash. Os testes unitários são inicializados, executado e limpo em um script bash. Este certificado contém um normalmete) funções (init (), executar () e limpeza. Mas eles não são obrigatórios. Eu gostaria de testar se eles são ou não são definidos.

Eu fiz isso anteriormente por greping e seding a fonte, mas parecia errado. Existe uma maneira mais elegante de fazer isso?

Edit: O seguinte sniplet funciona como um encanto:

fn_exists()
{
    LC_ALL=C type $1 | grep -q 'shell function'
}
Foi útil?

Solução

Eu acho que você está procurando o comando 'tipo'. Ele vai dizer se algo é uma função, built-in função, comando externo, ou simplesmente não definido. Exemplo:

$ LC_ALL=C type foo
bash: type: foo: not found

$ LC_ALL=C type ls
ls is aliased to `ls --color=auto'

$ which type

$ LC_ALL=C type type
type is a shell builtin

$ LC_ALL=C type -t rvm
function

$ if [ -n "$(LC_ALL=C type -t rvm)" ] && [ "$(LC_ALL=C type -t rvm)" = function ]; then echo rvm is a function; else echo rvm is NOT a function; fi
rvm is a function

Outras dicas

$ g() { return; }
$ declare -f g > /dev/null; echo $?
0
$ declare -f j > /dev/null; echo $?
1

Se declare é 10x mais rápido que teste, isto parece a resposta óbvia.

Edit: Abaixo, a opção -f é supérfluo com o bash, fique à vontade para deixá-lo fora. Pessoalmente, não tenho lembrança problemas que opção não que, então eu só usar os dois. -f mostra as funções, e -F mostra funcionar nomes.

#!/bin/sh

function_exists() {
    declare -f -F $1 > /dev/null
    return $?
}

function_exists function_name && echo Exists || echo No such function

A opção "-F" para declarar que ele faz para retornar apenas o nome da função encontrado, ao invés de todo o conteúdo.

Não deve haver qualquer penalidade de desempenho mensuráveis ??para usar / dev / null, e se preocupa tanto assim:

fname=`declare -f -F $1`
[ -n "$fname" ]    && echo Declare -f says $fname exists || echo Declare -f says $1 does not exist

Ou combinar os dois, para seu próprio prazer sem sentido. Ambos trabalho.

fname=`declare -f -F $1`
errorlevel=$?
(( ! errorlevel )) && echo Errorlevel says $1 exists     || echo Errorlevel says $1 does not exist
[ -n "$fname" ]    && echo Declare -f says $fname exists || echo Declare -f says $1 does not exist

O empréstimo de outras soluções e comentários, eu vim com isso:

fn_exists() {
  # appended double quote is an ugly trick to make sure we do get a string -- if $1 is not a known command, type does not output anything
  [ `type -t $1`"" == 'function' ]
}

Usado como ...

if ! fn_exists $FN; then
    echo "Hey, $FN does not exist ! Duh."
    exit 2
fi

verifica se o argumento dado é uma função, e evita redirecionamentos e outras grepping.

dragando um post antigo ... mas eu recentemente teve uso deste e testou ambas as alternativas descritas com:

test_declare () {
    a () { echo 'a' ;}

    declare -f a > /dev/null
}

test_type () {
    a () { echo 'a' ;}
    type a | grep -q 'is a function'
}

echo 'declare'
time for i in $(seq 1 1000); do test_declare; done
echo 'type'
time for i in $(seq 1 100); do test_type; done

este gerada:

real    0m0.064s
user    0m0.040s
sys     0m0.020s
type

real    0m2.769s
user    0m1.620s
sys     0m1.130s

declare é um helluvalot mais rápido!

Tudo se resume a usar 'Declare', quer verificar o código de saída ou saída.

estilo de saída:

isFunction() { [[ "$(declare -Ff "$1")" ]]; }

Uso:

isFunction some_name && echo yes || echo no

No entanto, se serve de memória, redirecionando para nula é mais rápido do que a substituição de saída (falando, o método `cmd` terrível e datada deve ser banido e US $ (cmd) usado.) E desde que declare retorna true / false se for encontrado / não encontrado, e funções retornam o código de saída do último comando na função para um retorno explícita normalmente não é necessário, e uma vez que a verificação do código de erro é mais rápido do que a verificação de um valor da cadeia (mesmo uma string null):

estilo status de saída:

isFunction() { declare -Ff "$1" >/dev/null; }

Isso é provavelmente tão sucinta e benigna que se pode chegar.

velocidade de teste de diferentes soluções

#!/bin/bash

f () {
echo 'This is a test function.'
echo 'This has more than one command.'
return 0
}

test_declare () {
    declare -f f > /dev/null
}

test_declare2 () {
    declare -F f > /dev/null
}

test_type () {
    type -t f | grep -q 'function'
}

test_type2 () {
    local var=$(type -t f)
    [[ "${var-}" = function ]]
}

post=
for j in 1 2; do
echo
echo 'declare -f' $post
time for i in $(seq 1 1000); do test_declare; done
echo
echo 'declare -F' $post
time for i in $(seq 1 1000); do test_declare2; done
echo
echo 'type with grep' $post
time for i in $(seq 1 1000); do test_type; done
echo
echo 'type with var' $post
time for i in $(seq 1 1000); do test_type2; done
unset -f f
post='(f unset)'
done

saídas por exemplo:.

declarar -f

0m0.037s reais 0m0.024s usuário sys 0m0.012s

declarar -F

0m0.030s reais 0m0.020s usuário sys 0m0.008s

tipo com grep

0m1.772s reais 0m0.084s usuário sys 0m0.340s

tipo com var

0m0.770s reais 0m0.096s usuário sys 0m0.160s

-f declare (f desactivado)

0m0.031s reais 0m0.028s usuário sys 0m0.000s

-F declare (f desactivado)

0m0.031s reais 0m0.020s usuário sys 0m0.008s

tipo com grep (f desactivado)

0m1.859s reais 0m0.100s usuário sys 0m0.348s

tipo com var (f desactivado)

0m0.683s reais 0m0.092s usuário sys 0m0.160s

Assim declare -F f && echo function f exists. || echo function f does not exist. parece ser a melhor solução.

fn_exists()
{
   [[ $(type -t $1) == function ]] && return 0
}

update

isFunc () 
{ 
    [[ $(type -t $1) == function ]]
}

$ isFunc isFunc
$ echo $?
0
$ isFunc dfgjhgljhk
$ echo $?
1
$ isFunc psgrep && echo yay
yay
$

Isto diz-lhe se ele existe, mas não que seja uma função

fn_exists()
{
  type $1 >/dev/null 2>&1;
}

Eu particularmente solução de Grégory Joseph

gostaram

Mas eu modifiquei um pouco para superar "quote truque dupla feia":

function is_executable()
{
    typeset TYPE_RESULT="`type -t $1`"

    if [ "$TYPE_RESULT" == 'function' ]; then
        return 0
    else
        return 1
    fi
}

Do meu comentário sobre uma outra resposta (que eu continuo faltando quando eu voltar a esta página)

$ fn_exists() { test x$(type -t $1) = xfunction; }
$ fn_exists func1 && echo yes || echo no
no
$ func1() { echo hi from func1; }
$ func1
hi from func1
$ fn_exists func1 && echo yes || echo no
yes

Eu melhorá-lo para:

fn_exists()
{
    type $1 2>/dev/null | grep -q 'is a function'
}

E usá-lo como este:

fn_exists test_function
if [ $? -eq 0 ]; then
    echo 'Function exists!'
else
    echo 'Function does not exist...'
fi

É possível usar 'tipo' sem quaisquer comandos externos, mas você tem que chamá-lo duas vezes, por isso ainda acaba por cerca de duas vezes mais lenta que a versão 'Declare':

test_function () {
        ! type -f $1 >/dev/null 2>&1 && type -t $1 >/dev/null 2>&1
}

Além disso, isso não funciona em POSIX sh, por isso é totalmente inútil, exceto como trivia!

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top