Ich habe bereits mehrmals darüber gesprochen, wie und warum die folgenden Methoden funktionieren, damit ich es nicht noch einmal mache. Persönlich sind meine eigenen Favoriten zum Thema hier und hier .
Wenn Sie sich bei der Lektüre nicht interessiert , aber immer noch neugierig nur verstehen , dass die hier docs , die Funktion des Eingangs angebracht sind für Shell - Erweiterung ausgewertet , bevor die Funktion ausgeführt wird , und dass sie neu erzeugt in dem Zustand , sie waren , als die Funktion definiert wurde jedes Mal, wenn die Funktion aufgerufen wird.
ERKLÄREN
Sie benötigen lediglich eine Funktion, die andere Funktionen deklariert.
_fn_init() { . /dev/fd/4 ; } 4<<INIT
${1}() { $(shift ; printf %s\\n "$@")
} 4<<-REQ 5<<-\\RESET
: \${_if_unset?shell will ERR and print this to stderr}
: \${common_param="REQ/RESET added to all funcs"}
REQ
_fn_init $(printf "'%s' " "$@")
RESET
INIT
STARTE ES
Hier rufe ich _fn_init
auf, mir eine aufgerufene Funktion zu deklarieren fn
.
set -vx
_fn_init fn \
'echo "this would be command 1"' \
'echo "$common_param"'
#OUTPUT#
+ _fn_init fn 'echo "this would be command 1"' 'echo "$common_param"'
shift ; printf %s\\n "$@"
++ shift
++ printf '%s\n' 'echo "this would be command 1"' 'echo "$common_param"'
printf "'%s' " "$@"
++ printf ''\''%s'\'' ' fn 'echo "this would be command 1"' 'echo "$common_param"'
#ALL OF THE ABOVE OCCURS BEFORE _fn_init RUNS#
#FIRST AND ONLY COMMAND ACTUALLY IN FUNCTION BODY BELOW#
+ . /dev/fd/4
#fn AFTER _fn_init .dot SOURCES IT#
fn() { echo "this would be command 1"
echo "$common_param"
} 4<<-REQ 5<<-\RESET
: ${_if_unset?shell will ERR and print this to stderr}
: ${common_param="REQ/RESET added to all funcs"}
REQ
_fn_init 'fn' \
'echo "this would be command 1"' \
'echo "$common_param"'
RESET
ERFORDERLICH
Wenn ich diese Funktion aufrufen möchte, stirbt sie, sofern die Umgebungsvariable nicht festgelegt _if_unset
ist.
fn
#OUTPUT#
+ fn
/dev/fd/4: line 1: _if_unset: shell will ERR and print this to stderr
Bitte beachten Sie die Reihenfolge der Shell-Traces - der fn
Fehler schlägt nicht nur fehl, wenn er aufgerufen wird, wenn er nicht festgelegt _if_unset
ist, sondern er wird überhaupt nicht ausgeführt . Dies ist der wichtigste Faktor, den Sie bei der Arbeit mit Here-Document-Erweiterungen verstehen sollten - sie müssen immer zuerst auftreten, weil sie es schließlich sind <<input
.
Der Fehler tritt auf, /dev/fd/4
weil die übergeordnete Shell diese Eingabe auswertet, bevor sie an die Funktion übergeben wird. Dies ist die einfachste und effizienteste Methode zum Testen der erforderlichen Umgebung.
Auf jeden Fall kann der Fehler leicht behoben werden.
_if_unset=set fn
#OUTPUT#
+ _if_unset=set
+ fn
+ echo 'this would be command 1'
this would be command 1
+ echo 'REQ/RESET added to all funcs'
REQ/RESET added to all funcs
FLEXIBEL
Die Variable common_param
wird bei der Eingabe für jede von deklarierte Funktion auf einen Standardwert ausgewertet _fn_init
. Dieser Wert kann aber auch in jeden anderen geändert werden, der auch von jeder ähnlich deklarierten Funktion berücksichtigt wird. Ich werde jetzt die Spuren der Muschel weglassen - wir betreten hier kein Neuland oder so.
set +vx
_fn_init 'fn' \
'echo "Hi! I am the first function."' \
'echo "$common_param"'
_fn_init 'fn2' \
'echo "This is another function."' \
'echo "$common_param"'
_if_unset=set ;
Oben deklariere ich zwei Funktionen und setze _if_unset
. Bevor ich eine der beiden Funktionen aufrufe, werde ich sie deaktivieren, common_param
damit Sie sehen können, dass sie sie selbst einstellen, wenn ich sie aufrufe.
unset common_param ; echo
fn ; echo
fn2 ; echo
#OUTPUT#
Hi! I am the first function.
REQ/RESET added to all funcs
This is another function.
REQ/RESET added to all funcs
Und jetzt aus dem Bereich des Anrufers:
echo $common_param
#OUTPUT#
REQ/RESET added to all funcs
Aber jetzt möchte ich, dass es etwas ganz anderes ist:
common_param="Our common parameter is now something else entirely."
fn ; echo
fn2 ; echo
#OUTPUT#
Hi! I am the first function.
Our common parameter is now something else entirely.
This is another function.
Our common parameter is now something else entirely.
Und wenn ich abgesetzt habe _if_unset
?
unset _if_unset ; echo
echo "fn:"
fn ; echo
echo "fn2:"
fn2 ; echo
#OUTPUT#
fn:
dash: 1: _if_unset: shell will ERR and print this to stderr
fn2:
dash: 1: _if_unset: shell will ERR and print this to stderr
RESET
Wenn Sie den Status der Funktion jederzeit zurücksetzen müssen, ist dies problemlos möglich. Sie müssen nur tun (innerhalb der Funktion):
. /dev/fd/5
Ich habe die Argumente, mit denen die Funktion ursprünglich deklariert wurde, im 5<<\RESET
Eingabedateideskriptor gespeichert. So .dot
Sourcing , dass jederzeit in der Shell den Vorgang wiederholen , die es bis in die erste Stelle gesetzt. Es ist wirklich alles ziemlich einfach und ziemlich vollständig portierbar, wenn Sie die Tatsache übersehen möchten, dass POSIX die Dateikonstruktions-Geräteknotenpfade (die für die Shell erforderlich sind) nicht wirklich spezifiziert .dot
.
Sie können dieses Verhalten leicht erweitern und verschiedene Zustände für Ihre Funktion konfigurieren.
MEHR?
Das kratzt übrigens kaum an der Oberfläche. Ich verwende diese Techniken oft, um kleine Hilfsfunktionen, die jederzeit deklarierbar sind, in die Eingabe einer Hauptfunktion einzubetten - zum Beispiel für zusätzliche Positionsarrays $@
nach Bedarf. In der Tat - wie ich glaube, muss es etwas sehr Nahes sein, das die Muscheln höherer Ordnung sowieso tun. Sie können sehen, dass sie sehr einfach programmgesteuert benannt werden.
Ich deklariere auch gerne eine Generatorfunktion, die einen begrenzten Parametertyp akzeptiert und dann eine Einweg- oder anderweitig bereichsbegrenzte Brennerfunktion nach dem Vorbild eines Lambda - oder einer Inline-Funktion - definiert, die sich einfach unset -f
selbst ergibt, wenn durch. Sie können eine Shell-Funktion weitergeben.
typeset
notwendig? Würde es es nicht anders erklären?