Was ist das zsh-Äquivalent von bashs export -f?

24

Also fing ich an zu benutzen zsh. Mir gefällt es gut. Es scheint sehr cool und flott zu sein, und die Tatsache, dass das aktuelle Arbeitsverzeichnis und die aktuelle Befehlszeile in verschiedenen Zeilen stehen, ist schön, aber gleichzeitig fällt mir auf, dass zshdies etwas langsamer sein kann als bash, insbesondere beim Drucken von Text auf Bildschirm.

Das, was mir am besten gefallen hat, war die Tatsache, dass zshes mit allen Funktionen, die ich in meinem definiert habe , "abwärtskompatibel" war .bashrc.

Ein Kritikpunkt. Die Funktionen funktionieren alle perfekt, aber ich kann nicht herausfinden, wie das Exportsystem funktioniert.

Ich habe einige dieser .bashrcFunktionen exportieren lassen, damit ich sie an anderer Stelle verwenden kann, z. B. in Skripten und externen Programmen mit export -f.

In zsh scheint nicht einmal über den Export gesprochen zu werden. Wird automatisch geladen? Sind diese beiden Dinge gleich? Es fällt mir schwer, das herauszufinden.

ixtmixilix
quelle
2
Dies ist eine sehr alte Frage, aber ich möchte sagen, dass "das aktuelle Arbeitsverzeichnis und die aktuelle Befehlszeile in verschiedenen Zeilen stehen" überhaupt nichts mit zsh zu tun hat. Es hängt davon ab, wie Sie Ihre Eingabeaufforderung eingerichtet haben, das ist alles.
4ae1e1

Antworten:

11

Umgebungsvariablen, die Funktionen enthalten, sind ein Bash-Hack. Zsh hat nichts ähnliches. Mit ein paar Codezeilen können Sie etwas Ähnliches tun. Umgebungsvariablen enthalten Zeichenfolgen. Ältere Versionen von bash haben vor der Entdeckung von Shellshock den Funktionscode in einer Variablen gespeichert, deren Name der der Funktion entspricht und auf deren Wert () {der Funktionscode folgt }. Mit dem folgenden Code können Sie Variablen mit dieser Codierung importieren und versuchen, sie mit bashartigen Einstellungen auszuführen. Beachten Sie, dass zsh nicht alle Bash-Funktionen emulieren kann. Sie können jedoch ein wenig näher heranrücken (z. B. um $fooden Wert zu teilen und Platzhalter zu erweitern und Arrays auf der Basis von 0 zu erstellen).

bash_function_preamble='
    emulate -LR ksh
'
for name in ${(k)parameters}; do
  [[ "-$parameters[name]-" = *-export-* ]] || continue
  [[ ${(P)name} = '() {'*'}' ]] || continue
  ((! $+builtins[$name])) || continue
  functions[$name]=$bash_function_preamble${${${(P)name}#"() {"}%"}"}
done

(Wie Stéphane Chazelas , der ursprüngliche Entdecker von Shellshock, feststellte, könnte eine frühere Version dieser Antwort an dieser Stelle beliebigen Code ausführen, wenn die Funktionsdefinition fehlerhaft ist. Dies gilt jedoch nicht, sobald Sie einen Befehl ausführen.) Es könnte sich um eine aus der Umgebung importierte Funktion handeln.)

Post-Shellshock-Versionen von bash codieren Funktionen in der Umgebung mit ungültigen Variablennamen (z BASH_FUNC_myfunc%%. B. ). Dies macht es schwieriger, sie zuverlässig zu analysieren, da zsh keine Schnittstelle zum Extrahieren solcher Variablennamen aus der Umgebung bietet.

Ich empfehle das nicht. Es ist eine schlechte Idee, sich auf exportierte Funktionen in Skripten zu verlassen: Sie erzeugen eine unsichtbare Abhängigkeit in Ihrem Skript. Wenn Sie Ihr Skript jemals in einer Umgebung ausführen, die nicht über Ihre Funktion verfügt (auf einem anderen Computer, in einem Cron-Job, nachdem Sie Ihre Shell-Initialisierungsdateien geändert haben, ...), funktioniert Ihr Skript nicht mehr. Speichern Sie stattdessen alle Ihre Funktionen in einer oder mehreren separaten Dateien (etwa ~/lib/shell/foo.sh) und starten Sie Ihre Skripte, indem Sie die verwendeten Funktionen importieren ( . ~/lib/shell/foo.sh). Wenn Sie Änderungen vornehmen foo.sh, können Sie auf diese Weise leicht nach den Skripten suchen, die darauf angewiesen sind. Wenn Sie ein Skript kopieren, können Sie leicht herausfinden, welche Zusatzdateien es benötigt.

Zsh (und ksh davor) erleichtert dies, indem Funktionen in Skripten, in denen sie verwendet werden, automatisch geladen werden. Die Einschränkung ist, dass Sie nur eine Funktion pro Datei einfügen können. Deklarieren Sie die Funktion als automatisch geladen und fügen Sie die Funktionsdefinition in eine Datei ein, deren Name der Name der Funktion ist. Legen Sie diese Datei in einem Verzeichnis ab $fpath(das Sie über die FPATHUmgebungsvariable konfigurieren können ). Deklarieren Sie in Ihrem Skript automatisch geladene Funktionen mit autoload -U foo.

Außerdem kann zsh Skripte kompilieren, um Parsing-Zeit zu sparen. Rufen Sie zcompileauf, um ein Skript zu kompilieren. Dadurch wird eine Datei mit der .zwcErweiterung erstellt. Wenn diese Datei vorhanden ist, autoloadwird die kompilierte Datei anstelle des Quellcodes geladen. Mit der zrecompileFunktion können Sie alle Funktionsdefinitionen in einem Verzeichnis (neu) kompilieren.

Gilles 'SO - hör auf böse zu sein'
quelle
1
Komisch, wie Ihr Code dieselbe Shellshock-Sicherheitsanfälligkeit aufweist bash(überprüft nicht, ob der Inhalt der Variablen nur eine Funktionsdefinition ist und verarbeitet einen Variablennamen wie HTTP_HOSToder LC_X). Gute Antwort ansonsten.
Stéphane Chazelas
@ StéphaneChazelas Wenn Sie Befehle mit aus der Umgebung importierten Funktionen ausführen, haben Sie so ziemlich verloren. Aber ich habe den Importcode aktualisiert, um keinen willkürlichen Code auszuführen. Es ist jedoch nicht sehr nützlich, da Post-Shellshock-Bash seine exportierten Funktionen nicht auf die gleiche Weise codiert.
Gilles 'SO- hör auf böse zu sein'
Sie haben jetzt das Äquivalent von CVE-2014-6271 behoben, sind jedoch wahrscheinlich noch vielen Schwachstellen des Typs CVE-2014-6277 / 6278 ausgesetzt, da Sie den zsh-Parser weiterhin für Code in einer beliebigen Variablen verfügbar machen darunter auch einige , die möglicherweise unter Kontrolle von Angreifern in bestimmten Kontexten (wie der Code in sind zsh -c 'functions[f]=$VAR' wird analysiert , auch wenn die fFunktion aufgerufen wird nie). Die Lösung besteht darin, nur Variablen zu berücksichtigen, deren Name einer reservierten Vorlage folgt $BASH_FUNC_x%%, die jedoch, wie Sie sagen, zshkeine API zum Auflisten oder Abrufen dieser enthält. Sie müssten zum Beispiel anrufen perl.
Stéphane Chazelas
7

Wenn Sie Ihre Funktionsdeklaration in .zshenv einfügen , kann Ihre Funktion mühelos aus einem Skript verwendet werden.

Scherze
quelle
Warum hast du meine Antwort abgelehnt? Bitte erkläre.
Rools
Ich warte immer noch auf eine Antwort und arbeite immer noch!
Rools
Ich habe diese Antwort gerade entdeckt und es ist eine ideale Lösung.
AFH
Ich habe es nicht abgelehnt. Und TBH the OP hat nach dem Exportieren von .bashrc gefragt, was eine schlechte Idee ist, besser, es in ein Skript zu schreiben, damit Sie nicht in eine riesige Umgebung geraten. Aber Ihre Lösung ist nur eine Variante derselben schlechten Idee. Fügen Sie alle Ihre Skripte ein .zshenvund verlangsamen Sie jeden Aufruf von zsh, indem Sie eine Menge Code analysieren, der nie benutzt wird. Außerdem ist es nicht dasselbe wie das Exportieren einer Funktion, genau wie eine exportierte Variable, eine exportierte Funktion ist nur für untergeordnete Prozesse verfügbar. Während die Sachen, die Sie in setzen, .zshenvzu jedem zsh verfügbar sind.
Metamorphic
Wenn Sie sich auf Ihren persönlichen Code verlassen .zshenv, sind alle Ihre Skripte nicht portierbar. Normalerweise könnten Skripte voneinander abhängen, was in Ordnung ist, Sie verteilen sie zusammen. Wenn sie jedoch von speziellen Funktionen abhängen .zshenv, wird niemand sie verwenden wollen oder sie müssten mit einem speziellen aufgerufen werden ZDOTDIR, um zu verhindern, dass Ihre eigenen Funktionen .zshenvausgeführt werden. Es wäre ein Schmerz.
Metamorphic