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.

8voto

jarno Punkte 687

Testen verschiedener Lösungen:

#!/bin/bash

test_declare () {
    declare -f f > /dev/null
}

test_declare2 () {
    declare -F f > /dev/null
}

test_type () {
    type -t f | grep -q 'function'
}

test_type2 () {
     [[ $(type -t f) = function ]]
}

funcs=(test_declare test_declare2 test_type test_type2)

test () {
    for i in $(seq 1 1000); do $1; done
}

f () {
echo 'This is a test function.'
echo 'This has more than one command.'
return 0
}
post='(f is function)'

for j in 1 2 3; do

    for func in ${funcs[@]}; do
        echo $func $post
        time test $func
        echo exit code $?; echo
    done

    case $j in
    1)  unset -f f
        post='(f unset)'
        ;;
    2)  f='string'
        post='(f is string)'
        ;;
    esac
done

Ausgänge z.B.:

test_declare (f ist Funktion)

real 0m0,055s user 0m0,041s sys 0m0,004s exit code 0

test_declare2 (f ist eine Funktion)

real 0m0,042s user 0m0,022s sys 0m0,017s exit code 0

test_type (f ist Funktion)

real 0m2,200s user 0m1,619s sys 0m1,008s exit code 0

test_type2 (f ist eine Funktion)

real 0m0,746s user 0m0,534s sys 0m0,237s exit code 0

test_declare (f unset)

real 0m0,040s user 0m0,029s sys 0m0,010s exit code 1

test_declare2 (f unset)

real 0m0,038s user 0m0,038s sys 0m0,000s exit code 1

test_type (f unset)

real 0m2,438s user 0m1,678s sys 0m1,045s exit code 1

test_type2 (f unset)

real 0m0,805s user 0m0,541s sys 0m0,274s exit code 1

test_declare (f ist string)

real 0m0,043s user 0m0,034s sys 0m0,007s exit code 1

test_declare2 (f ist string)

real 0m0,039s user 0m0,035s sys 0m0,003s exit code 1

test_type (f ist String)

real 0m2,394s user 0m1,679s sys 0m1,035s exit code 1

test_type2 (f ist String)

real 0m0,851s user 0m0,554s sys 0m0,294s exit code 1

Así que declare -F f scheint die beste Lösung zu sein.

7voto

Scott Punkte 71

Es läuft darauf hinaus, dass man mit 'declare' entweder die Ausgabe oder den Exit-Code überprüft.

Stil der Ausgabe:

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

Verwendung:

isFunction some_name && echo yes || echo no

Wenn ich mich recht erinnere, ist die Umleitung auf null jedoch schneller als die Ausgabesubstitution (apropos, die schreckliche und veraltete `cmd`-Methode sollte verbannt und stattdessen $(cmd) verwendet werden). Und da declare true/false zurückgibt, wenn es gefunden/nicht gefunden wurde, und Funktionen den Exit-Code des letzten Befehls in der Funktion zurückgeben, ist eine explizite Rückgabe normalerweise nicht notwendig, und da die Überprüfung des Fehlercodes schneller ist als die Überprüfung eines String-Wertes (sogar eines Null-Strings):

Beenden des Status Style:

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

Das ist wahrscheinlich die prägnanteste und harmloseste Formulierung, die man bekommen kann.

4voto

qneill Punkte 1565

Aus meinem Kommentar zu einer anderen Antwort (die ich immer wieder übersehe, wenn ich auf diese Seite zurückkomme)

$ 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

4voto

it3xl Punkte 1754

Aufruf einer Funktion, falls definiert.

Bekannter Funktionsname . Nehmen wir an, der Name lautet my_function verwenden, dann

[[ "$(type -t my_function)" == 'function' ]] && my_function;
# or
[[ "$(declare -fF my_function)" ]] && my_function;

Der Name der Funktion wird in einer Variablen gespeichert . Wenn wir erklären, dass func=my_function dann können wir

[[ "$(type -t $func)" == 'function' ]] && $func;
# or
[[ "$(declare -fF $func)" ]] && $func;

Die gleichen Ergebnisse mit || anstelle von &&
(Eine solche logische Umkehrung könnte bei der Codierung nützlich sein)

[[ "$(type -t my_function)" != 'function' ]] || my_function;
[[ ! "$(declare -fF my_function)" ]] || my_function;

func=my_function
[[ "$(type -t $func)" != 'function' ]] || $func;
[[ ! "$(declare -fF $func)" ]] || $func;

Strenger Modus und Vorbedingungsprüfungen
Wir haben set -e als strenger Modus.
Wir verwenden || return in unserer Funktion in einer Vorbedingung.
Dies zwingt unseren Shell-Prozess zum Beenden.

# Set a strict mode for script execution. The essence here is "-e"
set -euf +x -o pipefail

function run_if_exists(){
    my_function=$1

    [[ "$(type -t $my_function)" == 'function' ]] || return;

    $my_function
}

run_if_exists  non_existing_function
echo "you will never reach this code"

Dies ist eine Entsprechung von

set -e
function run_if_exists(){
    return 1;
}
run_if_exists

was Ihren Prozess abbricht.
Verwenden Sie || { true; return; } anstelle von || return; in Vorbedingungen, um dies zu beheben.

    [[ "$(type -t my_function)" == 'function' ]] || { true; return; }

3voto

Das sagt Ihnen, ob sie existiert, aber nicht, dass sie eine Funktion ist

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

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