233 Stimmen

Feststellen, ob eine Funktion in der Bash existiert

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(). Aber sie sind nicht zwingend erforderlich. Ich würde gerne testen, ob sie definiert sind oder nicht.

Ich habe dies bisher durch Greping und Seding des Quelltextes gemacht, aber es schien falsch zu sein. Gibt es einen eleganteren Weg, dies zu tun?

Edit: Das folgende Sniplet funktioniert wie ein Zauber:

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

0 Stimmen

Danke. Ich habe dies verwendet, um beim Laden einer Shell-Bibliothek bedingte Stubbed-Out-Versionen von Funktionen zu definieren. fn_exists foo || foo() { :; }

2 Stimmen

Sie können den Grep speichern, indem Sie type -t y == .

0 Stimmen

Funktioniert nicht, wenn das Gebietsschema nicht Englisch ist. type test_function sagt test_function on funktio. bei Verwendung des finnischen Gebietsschemas und ist eine Funktion wenn Sie Deutsch verwenden.

244voto

JBB Punkte 4215

Zum Beispiel so: [[ $(type -t foo) == function ]] && echo "Foo exists"

Die eingebaute type sagt Ihnen, ob etwas eine Funktion, eine eingebaute Funktion, ein externer Befehl oder einfach nicht definiert ist.

Weitere Beispiele:

$ 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

106voto

Allan Wind Punkte 10794

Der eingebaute Bash-Befehl declare hat eine Option -F die alle definierten Funktionsnamen anzeigt. Wenn Namensargumente angegeben werden, wird angezeigt, welche dieser Funktionen existieren, und wenn alle existieren, wird der Status entsprechend gesetzt:

$ fn_exists() { declare -F "$1" > /dev/null; }

$ unset f
$ fn_exists f && echo yes || echo no
no

$ f() { return; }
$ fn_exist f && echo yes || echo no
yes

47voto

Orwellophile Punkte 12151

Wenn die Deklaration 10x schneller ist als der Test, scheint dies die offensichtliche Antwort zu sein.

Bearbeiten: Unten, die -f ist bei BASH überflüssig, lassen Sie sie ruhig weg. Ich persönlich habe Schwierigkeiten, mir zu merken, welche Option was bewirkt, also verwende ich einfach beide. -f zeigt Funktionen, und -F zeigt Funktionsnamen an.

#!/bin/sh

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

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

Die Option "-F" für declare bewirkt, dass nur der Name der gefundenen Funktion und nicht der gesamte Inhalt zurückgegeben wird.

Es sollte keine messbaren Leistungseinbußen bei der Verwendung von /dev/null geben, und wenn es Sie so sehr beunruhigt:

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

Oder kombinieren Sie beides, zu Ihrem eigenen, sinnlosen Vergnügen. Sie funktionieren beide.

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

20voto

Grégory Joseph Punkte 1388

In Anlehnung an andere Lösungen und Kommentare habe ich mir folgendes ausgedacht:

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

Verwendet als ...

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

Es prüft, ob das angegebene Argument eine Funktion ist, und vermeidet Umleitungen und anderes Grepping.

11voto

jonathanserafini Punkte 229

Ich habe einen alten Beitrag wieder hervorgekramt ... aber ich hatte kürzlich Verwendung dafür und habe beide beschriebenen Alternativen getestet:

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

deklarieren ist verdammt viel schneller!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X