Determina se esiste una funzione in bash
Domanda
Attualmente sto eseguendo alcuni test unitari eseguiti da bash.Gli unit test vengono inizializzati, eseguiti e ripuliti in uno script bash.Questo script di solito contiene le funzioni init(),execute() e cleanup().Ma non sono obbligatori.Mi piacerebbe verificare se sono o non sono definiti.
L'ho fatto in precedenza greping e seding la fonte, ma sembrava sbagliato.Esiste un modo più elegante per farlo?
Modificare:Il seguente frammento funziona come un incantesimo:
fn_exists()
{
LC_ALL=C type $1 | grep -q 'shell function'
}
Soluzione
Penso che tu stia cercando il comando "tipo".Ti dirà se qualcosa è una funzione, una funzione incorporata, 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
Altri suggerimenti
$ g() { return; }
$ declare -f g > /dev/null; echo $?
0
$ declare -f j > /dev/null; echo $?
1
Se la dichiarazione è 10 volte più veloce del test, questa sembrerebbe la risposta ovvia.
Modificare:Di seguito, il -f
L'opzione è superflua con BASH, sentiti libero di lasciarla fuori.Personalmente, ho difficoltà a ricordare quale opzione fa quale, quindi le utilizzo entrambe. -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" da dichiarare fa sì che venga restituito solo il nome della funzione trovata, anziché l'intero contenuto.
Non dovrebbe esserci alcuna penalizzazione misurabile delle prestazioni per l'utilizzo 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
Oppure combina i due, per il tuo inutile divertimento.Funzionano entrambi.
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
Controlla se l'argomento fornito è una funzione ed evita reindirizzamenti e altri grepping.
Ripasso un vecchio post...ma recentemente l'ho utilizzato 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 è molto più veloce!
Si riduce all'uso di "dichiarare" per controllare l'output o il codice di uscita.
Stile di output:
isFunction() { [[ "$(declare -Ff "$1")" ]]; }
Utilizzo:
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 terribile e obsoleto metodo `cmd` dovrebbe essere bandito e utilizzato invece $(cmd).) E poiché dichiarato restituisce vero/falso se trovato/ non trovato e le funzioni restituiscono il codice di uscita dell'ultimo comando nella funzione, quindi di solito non è necessario un ritorno esplicito e poiché il controllo del codice di errore è più veloce del controllo di un valore di stringa (anche una stringa nulla):
Stile dello stato di uscita:
isFunction() { declare -Ff "$1" >/dev/null; }
Probabilmente è quanto di più conciso e benevolo si possa ottenere.
Velocità di test 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 esempio:
dichiarare -f
Real 0M0.037S Utente 0M0.024S SYS 0M0.012S
dichiarare -F
Real 0M0.030S Utente 0M0.020S SYS 0M0.008S
digitare con grep
Real 0M1.772S Utente 0M0.084S SYS 0M0.340S
digitare con var
reale 0m0.770s utente 0m0.096s sys 0m0.160s
dichiarare -f (f non impostato)
reale 0m0.031s utente 0m0.028s sys 0m0.000s
dichiarare -F (f non impostato)
Real 0M0.031S Utente 0M0.020S SYS 0M0.008S
digitare con grep (f non impostato)
Real 0M1.859S Utente 0M0.100S SYS 0M0.348S
digitare con var (f non impostato)
Real 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
}
aggiornamento
isFunc ()
{
[[ $(type -t $1) == function ]]
}
$ isFunc isFunc
$ echo $?
0
$ isFunc dfgjhgljhk
$ echo $?
1
$ isFunc psgrep && echo yay
yay
$
Questo ti dice se esiste, ma non che sia una funzione
fn_exists()
{
type $1 >/dev/null 2>&1;
}
Mi è particolarmente piaciuta la soluzione di Gregorio Giuseppe
Ma l'ho modificato un po' per superare il "brutto trucco delle virgolette doppie":
function is_executable()
{
typeset TYPE_RESULT="`type -t $1`"
if [ "$TYPE_RESULT" == 'function' ]; then
return 0
else
return 1
fi
}
Dal mio commento su un'altra risposta (che continuo a perdere quando torno su 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 in:
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 alcun comando esterno, ma devi chiamarlo due volte, quindi risulta comunque 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 se non come curiosità!