Frage

Derzeit mache ich einige Unit-Tests, die von Bash ausgeführt werden.Unit-Tests werden in einem Bash-Skript initialisiert, ausgeführt und bereinigt.Dieses Skript enthält normalerweise die Funktionen „init()“, „execute()“ und „cleanup()“.Sie sind aber nicht verpflichtend.Ich würde gerne testen, ob sie definiert sind oder nicht.

Ich habe dies zuvor getan, indem ich die Quelle ausgesucht und gelöscht habe, aber es schien falsch zu sein.Gibt es eine elegantere Möglichkeit, dies zu tun?

Bearbeiten:Das folgende Sniplet funktioniert wie ein Zauber:

fn_exists()
{
    LC_ALL=C type $1 | grep -q 'shell function'
}
War es hilfreich?

Lösung

Ich glaube, du bist für den ‚Typ‘ Befehl suchen. Es wird Ihnen sagen, ob etwas eine Funktion, integrierte Funktion, externer Befehl ist, oder einfach nur nicht definiert. Beispiel:

$ 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

Andere Tipps

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

Wenn declare 10x schneller als Test ist, würde dies die offensichtliche Antwort scheint.

Edit: Unten die -f Option mit BASH überflüssig ist, können Sie es wegzulassen. Persönlich habe ich Probleme Erinnern, die Option tut das, so dass ich nur beide verwenden. -f zeigt Funktionen und F zeigt Funktionsnamen.

#!/bin/sh

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

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

Die Option „-f“ Ursachen zu erklären, um es nur den Namen der gefundenen Funktion zurückzukehren, anstatt den gesamten Inhalt.

Es sollte keine messbaren Leistungs Strafe für die Verwendung von / dev / null, und wenn es Ihnen Sorgen, dass viel:

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

oder kombinieren die beiden, für Ihre eigenen sinnlos Genuss. Beide arbeiten.

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

Ausleihe von anderen Lösungen und Kommentaren, ich kam mit dieser:

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' ]
}

Wird als ...

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

Es wird überprüft, ob das angegebene Argument eine Funktion ist, und vermeidet Umleitungen und andere Grepping.

Ausbaggern einen alten Post ... aber ich hatte vor kurzem Gebrauch dieses und getestet beiden Alternativen beschrieben mit:

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

Dies erzeugt:

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

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

declare ist ein helluvalot schneller!

Es läuft darauf hinaus, „declare“ zu verwenden, um entweder die Ausgabe oder den Exit-Code zu überprüfen.

Ausgabestil:

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

Verwendung:

isFunction some_name && echo yes || echo no

Wenn jedoch Speicher ausreicht, ist die Umleitung auf null schneller als die Ausgabeersetzung (apropos, die schreckliche und veraltete „cmd“-Methode sollte verbannt und stattdessen $(cmd) verwendet werden.) Und da „declare“ „true/false“ zurückgibt, wenn sie gefunden wird/ nicht gefunden und Funktionen geben den Exit-Code des letzten Befehls in der Funktion zurück, sodass eine explizite Rückgabe normalerweise nicht erforderlich ist und da die Überprüfung des Fehlercodes schneller ist als die Überprüfung eines Zeichenfolgenwerts (sogar einer Nullzeichenfolge):

Exit-Statusstil:

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

Das ist wahrscheinlich so prägnant und harmlos, wie es nur geht.

Testgeschwindigkeit verschiedener Lösungen

#!/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

Ausgänge z.B.:

deklariere -f

Real 0M0.037S Benutzer 0M0.024S SYS 0M0.012S

deklarieren -F

Real 0M0.030S Benutzer 0M0.020S SYS 0M0.008S

Geben Sie mit grep ein

Real 0M1.772S Benutzer 0M0.084S SYS 0M0.340S

Typ mit var

Real 0M0.770S Benutzer 0M0.096S SYS 0M0.160S

deklarieren -f (f nicht gesetzt)

Real 0m0.031s Benutzer 0M0.028S SYS 0M0.000S

deklarieren -F (f nicht gesetzt)

Real 0m0.031s Benutzer 0M0.020S SYS 0M0.008S

Typ mit grep (f unset)

Real 0M1.859S Benutzer 0M0.100S SYS 0M0.348S

Typ mit var (f nicht gesetzt)

Real 0m0.683s Benutzer 0M0.092S SYS 0M0.160S

Also declare -F f && echo function f exists. || echo function f does not exist. scheint die beste Lösung zu sein.

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
$

Dies sagt Ihnen, wenn es vorhanden ist, aber nicht, dass es eine Funktion

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

ich besonders mochte Lösung von Grégory Joseph

Aber ich habe es ein wenig verändert „doppelte Anführungszeichen hässlich Trick“ zu überwinden:

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

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

Von meinem Kommentar zu einer anderen Antwort (was ich vermisste halten, wenn ich auf dieser Seite zurückkommen)

$ 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

ich verbessern würde es an:

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

Und es wie folgt verwendet werden:

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

Es ist möglich, zu verwenden ‚Typen‘ ohne externe Befehle, aber Sie haben sie zweimal zu nennen, so dass es endet immer noch etwa doppelt so langsam wie die ‚declare‘ -Version:

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

Plus das funktioniert nicht in POSIX sh, so ist es völlig wertlos, außer als Haupt!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top