linux - paso - scripts bash ejemplos
Determinar si existe una función en bash (13)
Actualmente estoy haciendo algunas pruebas unitarias que se ejecutan desde bash. Las pruebas unitarias se inicializan, ejecutan y limpian en un script bash. Este script normalmente contiene una función init (), execute () y cleanup (). Pero no son obligatorios. Me gustaría probar si están o no definidos.
Hice esto previamente greping y seding la fuente, pero parecía estar equivocado. ¿Hay una manera más elegante de hacer esto?
Editar: el siguiente sniplet funciona como un amuleto:
fn_exists()
{
type $1 | grep -q ''shell function''
}
Arrastrando una publicación anterior ... pero recientemente tuve el uso de esto y probé las dos alternativas descritas con:
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
esto generó:
real 0m0.064s
user 0m0.040s
sys 0m0.020s
type
real 0m2.769s
user 0m1.620s
sys 0m1.130s
declarar es un helluvalot más rápido!
Creo que estás buscando el comando ''tipo''. Te dirá si algo es una función, una función incorporada, un comando externo o simplemente no está definido. Ejemplo:
$ type foo
bash: type: foo: not found
$ type ls
ls is aliased to `ls --color=auto''
$ which type
$ type type
type is a shell builtin
$ type -t rvm
function
$ if [ -n "$(type -t rvm)" ] && [ "$(type -t rvm)" = function ]; then echo rvm is a function; else echo rvm is NOT a function; fi
rvm is a function
De mi comentario sobre otra respuesta (que sigo perdiendo cuando vuelvo 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
Es posible usar ''tipo'' sin ningún comando externo, pero tiene que llamarlo dos veces, por lo que aún termina el doble de lento que la versión ''declarar'':
test_function () {
! type -f $1 >/dev/null 2>&1 && type -t $1 >/dev/null 2>&1
}
Además, esto no funciona en POSIX sh, por lo que es totalmente inútil excepto como trivia!
Esto te dice si existe, pero no que sea una función
fn_exists()
{
type $1 >/dev/null 2>&1;
}
Lo mejoraría a:
fn_exists()
{
type $1 2>/dev/null | grep -q ''is a function''
}
Y úsalo así:
fn_exists test_function
if [ $? -eq 0 ]; then
echo ''Function exists!''
else
echo ''Function does not exist...''
fi
Me gustó especialmente la solución de Grégory Joseph
Pero lo he modificado un poco para superar el "truco feo de doble cita":
function is_executable()
{
typeset TYPE_RESULT="`type -t $1`"
if [ "$TYPE_RESULT" == ''function'' ]; then
return 0
else
return 1
fi
}
Si declarar es 10 veces más rápido que la prueba, esta parece ser la respuesta obvia.
Editar: A continuación, la opción -f
es superflua con BASH, no dudes en omitirla. Personalmente, tengo problemas para recordar qué opción hace cuáles, así que solo uso ambas. -f muestra funciones, y -F muestra nombres de funciones.
#!/bin/sh
function_exists() {
declare -f -F $1 > /dev/null
return $?
}
function_exists function_name && echo Exists || echo No such function
La opción "-F" para declarar hace que solo devuelva el nombre de la función encontrada, en lugar de todo el contenido.
No debería haber ninguna penalización de rendimiento mensurable para usar / dev / null, y si te preocupa tanto:
fname=`declare -f -F $1`
[ -n "$fname" ] && echo Declare -f says $fname exists || echo Declare -f says $1 does not exist
O combine los dos, para su propio disfrute sin sentido. Ambos trabajan.
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
Todo se reduce a usar ''declarar'' para verificar el código de salida o de salida.
Estilo de salida:
isFunction() { [[ "$(declare -Ff "$1")" ]]; }
Uso:
isFunction some_name && echo yes || echo no
Sin embargo, si la memoria sirve, redirigir a nulo es más rápido que la sustitución de salida (hablando de, el método `cmd` horrible y obsoleto debe ser desterrado y $ (cmd) utilizado en su lugar.) Y desde declarar devuelve verdadero / falso si se encuentra / no encontrado, y las funciones devuelven el código de salida del último comando en la función, por lo que normalmente no es necesario un retorno explícito, y dado que verificar el código de error es más rápido que verificar un valor de cadena (incluso una cadena nula):
Estilo de estado de salida:
isFunction() { declare -Ff "$1" >/dev/null; }
Probablemente sea tan breve y benigno como puedas.
Tomando prestado de otras soluciones y comentarios, se me ocurrió esto:
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
Comprueba si el argumento dado es una función y evita las redirecciones y otras reducciones.
Velocidad de prueba de diferentes soluciones
#!/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
salidas, por ejemplo:
declarar -f
usuario real 0m0.037s 0m0.024s sys 0m0.012s
declarar -F
usuario real 0m0.030s 0m0.020s sys 0m0.008s
escribe con grep
usuario real 0m1.772s 0m0.084s sys 0m0.340s
escribir con var
usuario real 0m0.770s 0m0.096s sys 0m0.160s
declarar -f (f unset)
usuario real 0m0.031s 0m0.028s sys 0m0.000s
declarar -F (f unset)
usuario real 0m0.031s 0m0.020s sys 0m0.008s
escriba con grep (f unset)
usuario real 0m1.859s 0m0.100s sys 0m0.348s
escriba con var (f unset)
usuario real 0m0.683s 0m0.092s sys 0m0.160s
Por lo tanto, declare -F f && echo function f exists. || echo function f does not exist.
declare -F f && echo function f exists. || echo function f does not exist.
parece ser la mejor solución.
$ g() { return; }
$ declare -f g > /dev/null; echo $?
0
$ declare -f j > /dev/null; echo $?
1
fn_exists()
{
[[ $(type -t $1) == function ]] && return 0
}
actualizar
isFunc ()
{
[[ $(type -t $1) == function ]]
}
$ isFunc isFunc
$ echo $?
0
$ isFunc dfgjhgljhk
$ echo $?
1
$ isFunc psgrep && echo yay
yay
$