Attualmente sto facendo alcuni test unitari che vengono eseguiti da bash. I test unitari vengono inizializzati, eseguiti e ripuliti in uno script bash. Questo script di solito contiene una init (), execute () e cleanup () funzioni. Ma non sono obbligatori. Mi piacerebbe testare se sono o non sono definiti.
L'ho fatto in precedenza bestemmiando e sedando la fonte, ma sembrava sbagliato. C'è un modo più elegante per farlo?
Modifica: il seguente sniplet funziona come un incantesimo:
fn_exists()
{
LC_ALL=C type $1 | grep -q 'Shell function'
}
Penso che tu stia cercando il comando 'type'. Ti dirà se qualcosa è una funzione, una funzione integrata, un comando esterno o semplicemente non definito. Esempio:
$ 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
$ g() { return; }
$ declare -f g > /dev/null; echo $?
0
$ declare -f j > /dev/null; echo $?
1
Se dichiarare è 10 volte più veloce del test, questa sembrerebbe la risposta ovvia.
Modifica: sotto, il -f
L'opzione è superflua con BASH, sentiti libero di lasciarla fuori. Personalmente, ho difficoltà a ricordare quale opzione fa quale, quindi uso semplicemente entrambi. - f mostra le funzioni e - F mostra i nomi delle funzioni.
#!/bin/sh
function_exists() {
declare -f -F $1 > /dev/null
return $?
}
function_exists function_name && echo Exists || echo No such function
L'opzione "-F" per dichiarare fa sì che restituisca solo il nome della funzione trovata, anziché l'intero contenuto.
Non ci dovrebbe essere alcuna penalità di prestazione misurabile per l'uso di/dev/null e se ti preoccupa così tanto:
fname=`declare -f -F $1`
[ -n "$fname" ] && echo Declare -f says $fname exists || echo Declare -f says $1 does not exist
O combina i due, per il tuo divertimento inutile. Entrambi funzionano.
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
Prendendo in prestito da altre soluzioni e commenti, ho pensato a questo:
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' ]
}
Usato come ...
if ! fn_exists $FN; then
echo "Hey, $FN does not exist ! Duh."
exit 2
fi
Verifica se l'argomento dato è una funzione ed evita reindirizzamenti e altri grepping.
Eliminare un vecchio post ... ma recentemente ne ho fatto uso e ho testato entrambe le alternative descritte 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
questo ha generato:
real 0m0.064s
user 0m0.040s
sys 0m0.020s
type
real 0m2.769s
user 0m1.620s
sys 0m1.130s
dichiarare è un helluvalot più veloce!
Si riduce a usare 'dichiarare' per controllare il codice di uscita o di uscita.
Stile di uscita:
isFunction() { [[ "$(declare -Ff "$1")" ]]; }
Uso:
isFunction some_name && echo yes || echo no
Tuttavia, se la memoria serve, il reindirizzamento a null è più veloce della sostituzione dell'output (a proposito, il metodo `cmd` terribile e obsoleto dovrebbe essere bandito e dovrebbe essere usato $ (cmd).) E poiché dichiarare restituisce vero/falso se trovato/non trovato e le funzioni restituiscono il codice di uscita dell'ultimo comando nella funzione, pertanto un ritorno esplicito di solito non è necessario e poiché la verifica del codice di errore è più rapida della verifica di un valore di stringa (anche una stringa nulla):
Stile stato di uscita:
isFunction() { declare -Ff "$1" >/dev/null; }
Questo è probabilmente il più succinto e benigno possibile.
Test di velocità di diverse soluzioni
#!/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
uscite ad es .:
dichiarare -f
reale 0m0.037s utente 0m0.024s sys 0m0.012s
dichiarare -F
reale 0m0.030s utente 0m0.020s sys 0m0.008s
digitare con grep
reale 0m1.772s utente 0m0.084s sys 0m0.340s
digitare con var
reale 0m0.770s utente 0m0.096s sys 0m0.160s
dichiarare -f (f unset)
reale 0m0.031s utente 0m0.028s sys 0m0.000s
dichiarare -F (f unset)
reale 0m0.031s utente 0m0.020s sys 0m0.008s
digitare con grep (f non impostato)
reale 0m1.859s utente 0m0.100s sys 0m0.348s
digitare con var (f unset)
reale 0m0.683s utente 0m0.092s sys 0m0.160s
Così declare -F f && echo function f exists. || echo function f does not exist.
sembra essere la soluzione migliore.
fn_exists()
{
[[ $(type -t $1) == function ]] && return 0
}
pdate
isFunc ()
{
[[ $(type -t $1) == function ]]
}
$ isFunc isFunc
$ echo $?
0
$ isFunc dfgjhgljhk
$ echo $?
1
$ isFunc psgrep && echo yay
yay
$
Mi è piaciuta particolarmente la soluzione di Grégory Joseph
Ma l'ho modificato un po 'per superare il "brutto trucco della doppia virgoletta":
function is_executable()
{
typeset TYPE_RESULT="`type -t $1`"
if [ "$TYPE_RESULT" == 'function' ]; then
return 0
else
return 1
fi
}
Questo ti dice se esiste, ma non che sia una funzione
fn_exists()
{
type $1 >/dev/null 2>&1;
}
Dal mio commento su un'altra risposta (che mi manca quando torno a questa pagina)
$ 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
Lo migliorerei per:
fn_exists()
{
type $1 2>/dev/null | grep -q 'is a function'
}
E usalo in questo modo:
fn_exists test_function
if [ $? -eq 0 ]; then
echo 'Function exists!'
else
echo 'Function does not exist...'
fi
È possibile utilizzare 'type' senza comandi esterni, ma è necessario chiamarlo due volte, quindi finisce circa due volte più lento della versione 'declare':
test_function () {
! type -f $1 >/dev/null 2>&1 && type -t $1 >/dev/null 2>&1
}
Inoltre questo non funziona in POSIX sh, quindi è totalmente inutile tranne che per curiosità!