foo='foo(){ echo "Inside Function"; }'
bash -c "$foo; foo"
Inside Function
Eine Funktion ist schließlich einfach eine benannte, vorab analysierte statische Befehlszeichenfolge, die im Speicher der Shell gespeichert ist. Der einzige wirkliche Weg, dies zu tun, besteht darin, Zeichenfolgen als Code auszuwerten. Genau das tut die Shell jedes Mal, wenn Sie Ihre Funktion aufrufen.
Es war noch nie so anders und ist es immer noch nicht. Die Entwickler richten hierfür bequeme Methoden ein und versuchen, mögliche Sicherheitslücken so gut wie möglich zu schützen. Tatsache ist jedoch, dass je bequemer eine Sache wird, desto wahrscheinlicher ist es, dass Sie weniger darüber wissen, als Sie sollten.
Es gibt viele Optionen zur Verfügung , wenn es darum geht , Daten von den Eltern Schalen Subshells zu importieren. Machen Sie sich mit ihnen vertraut, werden Sie sicher genug, dass Sie ihre potenziellen Verwendungszwecke und ihre potenziellen Schwächen identifizieren und sie sparsam, aber effektiv einsetzen können.
Ich nehme an, ich kann ein oder zwei davon näher erläutern, während ich dabei bin. Der wahrscheinlich beste Weg, um statische Befehle von einer Shell an eine andere zu übergeben (egal ob es sich um eine untergeordnete Befehlskette handelt oder nicht), ist alias
. alias
ist in dieser Funktion nützlich, da es POSIX-spezifiziert ist , um seine definierten Befehle sicher zu melden :
Das Format für die Anzeige von Aliasen (wenn keine Operanden oder nur Namensoperanden angegeben sind) muss sein:
Die Wertzeichenfolge muss mit entsprechenden Anführungszeichen geschrieben werden, damit sie für die erneute Eingabe in die Shell geeignet ist. Siehe die Beschreibung des Shell-Zitierens in Quoting .
Zum Beispiel:
alias foo="foo(){ echo 'Inside Function'; }"
alias foo
foo='foo(){ echo '\''Inside Function'\''; }'
Sehen Sie, was es dort mit den Zitaten macht? Die genaue Ausgabe hängt von der Shell ab. Im Allgemeinen können Sie sich jedoch darauf verlassen, dass eine Shell ihre alias
Definitionen auf eine Weise eval
meldet, die für die erneute Eingabe in dieselbe Shell sicher ist . Das Mischen und Anpassen von Quell- / Ziel-Shells kann jedoch in einigen Fällen zweifelhaft sein.
Um einen Grund für diese Vorsicht aufzuzeigen:
ksh -c 'alias foo="
foo(){
echo \"Inside Function\"
}"
alias foo'
foo=$'\nfoo(){\n\techo "Inside Function"\n}'
Beachten Sie auch, dass der alias
Namespace einen von drei unabhängigen Namespaces darstellt, von denen Sie allgemein erwarten können, dass sie in praktisch jeder modernen Shell vollständig ausgearbeitet sind. In der Regel bieten Shells diese drei Namespaces:
Variablen: name=value
außerhalb von Listen
- Diese können auch mit einigen eingebauten Funktionen wie definiert werden
export
, set
, readonly
in einigen Fällen.
Funktionen: name() compound_command <>any_redirects
in Befehlsposition
- Die Schale ist angegeben nicht zu erweitern oder einen beliebigen Teil der Funktionsdefinition zu interpretieren es in dem Befehl zur Definitionszeit finden könnte.
- Dieses Verbot enthält jedoch keine Aliase, da diese während des Analyseprozesses des Lesens eines Shell-Befehls erweitert werden und
alias
Werte, wenn alias
sie im richtigen Kontext gefunden werden, beim Auffinden in den Funktionsdefinitionsbefehl erweitert werden.
- Wie bereits erwähnt, speichert die Shell den analysierten Wert des Definitionsbefehls als statische Zeichenfolge in ihrem Speicher und führt alle in der Zeichenfolge gefundenen Erweiterungen und Umleitungen nur aus, wenn der Funktionsname später nach dem Parsen wie aufgerufen gefunden wird.
Aliase: alias name=value
in Kommandoposition
- Wie Funktionen werden
alias
Definitionen interpretiert, wenn die Definitionsnamen später an der Befehlsposition gefunden werden.
- Im Gegensatz zu Funktionen werden
alias
gültige Shell-Erweiterungen, die darin enthalten sind, zum definierten Zeitpunkt ebenfalls interpretiert , da ihre Definitionen Argumente für den Befehl sind. Und so werden alias
Definitionen immer zweimal interpretiert.
- Im Gegensatz zu Funktionen werden
alias
Definitionen zur Definitionszeit überhaupt nicht analysiert, sondern es ist der Parser der Shell, der ihre Werte vor dem Parsen in eine Befehlszeichenfolge erweitert, wenn sie gefunden werden.
Sie haben wahrscheinlich bemerkt, was meiner Meinung nach der Hauptunterschied zwischen einer alias
oder einer Funktion oben ist, die der Expansionspunkt der Shell für jede Funktion ist. Die Unterschiede können ihre Kombination tatsächlich sehr nützlich machen.
alias foo='
foo(){
printf "Inside Function: %s\n" "$@"
unset -f foo
}; foo "$@" '
Dies ist ein Alias, der eine Funktion definiert, die sich beim Aufruf selbst aufhebt und daher einen Namespace durch die Anwendung eines anderen beeinflusst. Es ruft dann die Funktion auf. Das Beispiel ist naiv; In einem regulären Kontext ist es nicht sehr nützlich, aber das folgende Beispiel zeigt möglicherweise eine andere eingeschränkte Nützlichkeit, die es in anderen Kontexten bietet:
sh -c "
alias $(alias foo)
foo \'
" -- \; \' \" \\
Inside Function: ;
Inside Function: '
Inside Function: "
Inside Function: \
Inside Function: '
Sie sollten immer einen alias
Namen in einer anderen Eingabezeile als der aufrufen, in der sich die Definition befindet. Dies hängt wiederum mit der Analysereihenfolge des Befehls zusammen. In Kombination können Aliase und Funktionen zusammen verwendet werden, um Informationen und Parameterarrays portabel, sicher und effektiv in und aus Subshelled-Kontexten zu verschieben.
Fast ohne Beziehung, aber hier ist noch eine lustige:
alias mlinesh='"${SHELL:-sh}" <<"" '
Führen Sie dies an einer interaktiven Eingabeaufforderung aus, und alle Argumente, die Sie in derselben Ausführungszeile wie die Zeile, in der Sie es aufrufen, übergeben, werden als Argumente für eine Subshell interpretiert. Alle Zeilen danach bis zur ersten auftretenden Leerzeile werden jedoch von der aktuellen Shell eingelesen, um als Standard an die Subshell zu übergeben, die sie zum Aufrufen vorbereitet, und keine dieser Zeilen wird in irgendeiner Weise interpretiert.
$ mlinesh -c '. /dev/fd/0; foo'
> foo(){ echo 'Inside Function'; }
>
Inside Function
... aber nur ...
$ mlinesh
> foo(){ echo 'Inside Function'; }
> foo
>
...ist einfacher...
foo() { echo "Inside function"; }; foo
?