So exportieren Sie Umgebungsvariablen, die Leerzeichen enthalten, korrekt in ZSH

So exportieren Sie Umgebungsvariablen, die Leerzeichen enthalten, korrekt in ZSH

Fügen Sie eine Umgebungsvariable mit Leerzeichen hinzu, um~/.zshrc

export SKIP="-Dskip1 -Dskip2"
export SKIP_NO_SPACES="-Dskip3"

Versuchen Sie es zu verwenden

set -x  
mvn $SKIP $SKIP_NO_SPACES

Der ausgeführte Befehl ist eigentlich

+-zsh:108> mvn '-Dskip1 -Dskip2' -Dskip3

Nur die Variable, die Leerzeichen enthält, wird in Anführungszeichen gesetzt.

Wie vermeidet man das Hinzufügen einfacher Anführungszeichen?

Wenn Sie Anführungszeichen/Escapezeichen überhaupt nicht verwenden, tritt beim Öffnen der Shell ein Fehler auf:

/.zshrc:export:11: in diesem Kontext nicht gültig: -Dskip2

Antwort1

Ich glaube, Sie missbrauchen hier (irgendwie) Umgebungsvariablen. Dieser Leerraum ist Teil der Variable, und wenn Sie eine Parametererweiterung mit durchführen $, wird dieser Leerraum einfach an den Befehl übergeben. mvnerhält ein Argument – ​​den Inhalt Ihrer Variable.

Wie Kamil Maciorowski in einem Kommentar richtig bemerkt, ist dies spezifisch für Zsh. Was Sie vorschlagen, würde in Bash funktionieren, wenn Sie die Anführungszeichen weglassen würden:

bash-5.0$ export test="foo bar"
bash-5.0$ ls $test
ls: bar: No such file or directory
ls: foo: No such file or directory
bash-5.0$ ls "$test"
ls: foo bar: No such file or directory

Eine Alternative zu tun, was Sie wollen, wäre einglobaler Alias(auch eine Funktion von Zsh, nicht von Bash), die überall in einer Zeile ersetzt werden kann. Sie behält ihre Leerzeichen:

$ alias -g SKIP="-Dskip1 -Dskip2"
$ alias -g SKIP2="-Dskip3"
$ mvn SKIP SKIP2

Dadurch wird die Zeichenfolge einfach an der hinzugefügten Stelle „angehängt“.

Antwort2

Das Problem hat nichts mit Anführungszeichen oder Escapezeichen zu tun, sondern mit der Worttrennung (oder dem Fehlen derselben). Wenn Sie in den meisten Shells eine Variable verwenden, die Leerzeichen enthält, ohne sie in Anführungszeichen zu setzen, wird der Wert basierend auf diesen Leerzeichen in „Wörter“ aufgeteilt. Wenn die Variable also SKIPauf gesetzt ist -Dskip1 -Dskip2(beachten Sie, dass dieser Wert keine Anführungszeichen oder Escapezeichen enthält) und Sie sie wie verwenden mvn $SKIP, wird sie gleichwertig mit mvn "-Dskip1" "-Dskip2".

Aber zsh ist nicht wie die meisten Shells und (standardmäßig) führt es keine Worttrennung durch. Wenn die Variable auf gesetzt ist -Dskip1 -Dskip2, wird das an den Befehl übergeben,als einzelnes Argument. Die Anführungszeichen, die Sie in der set -xAusgabe sehen, sind nicht wirklich da, sie werden nur hinzugefügt, um deutlich zu machen, dass die gesamte Zeichenfolge als einzelnes Argument übergeben wird.

Es gibt mehrere Möglichkeiten, zsh mitzuteilen, dass Sie eine Worttrennung durchführen möchten. Sie können den =Modifikator in der Erweiterung verwenden:

mvn ${=SKIP}

Oder Sie können die sh-ähnliche Aufteilung für alle Erweiterungen mit einer Shell-Option aktivieren:

setopt shwordsplit
mvn $SKIP

...das kann jedoch unangenehme Nebeneffekte haben, wie z. B. eine unerwartete Aufteilung von Dingen, die Sie für einzelne Argumente gehalten haben, und die Erweiterung von allem, was wie ein Platzhalter für Dateinamen aussieht, in eine Liste von Dateinamen. Die Wortaufteilung in der Shell neigt dazu, Fehler zu verursachen, weshalb sie in zsh standardmäßig deaktiviert ist. Die wirklich richtige Art, mehrere Zeichenfolgen in einer Variablen zu speichern, besteht darin, ein Array anstelle einer einfachen Variablen zu verwenden:

SKIP=(-Dskip1 -Dskip2)
mvn "${SKIP[@]}"

Dies funktioniert in zsh, bash und einigen anderen Shells (aber nicht in denen ohne Array-Unterstützung). Sie können jedoch keine Arrays aus zsh exportieren (Sie können zwar ausführen export SKIP, aber das passiert nichts). Arrays sind eine Shell-Funktion, während Umgebungsvariablen eine Betriebssystemfunktion sind, die nur einfache Zeichenfolgen unterstützt. Müssen Sie diese Optionen wirklich exportieren oder verwenden Sie sie nur innerhalb der Shell?

Antwort3

In der Diagnosezeile erscheinen einfache Anführungszeichen aufgrund von set -x. Sie gelangen nicht zu mvn. Der Variableninhalt ( -Dskip1 -Dskip2) gelangt zu mvnals einzelnes Argument, da zshSie in Variablen nicht starr in Anführungszeichen setzen müssen (in POSIX-kompatiblen Shells tun Sie das).

Das Problem scheint in der Art und Weise zu liegen, wie zshVariablen erweitert werden. Ich denke, Sie möchten, dass die Worttrennung erfolgt, wenn $SKIPnicht in Anführungszeichen steht (wie es in anderen Muscheln passiertzsh), kommt aber normalerweise nicht vor.

Verwenden Sie ${=SKIP}fürTriggerwortaufteilung nach Ersetzung.

Beispiel:

% SKIP='-Dskip1 -Dskip2' 
% printf "%s\n" $SKIP   
-Dskip1 -Dskip2
% printf "%s\n" ${=SKIP}
-Dskip1
-Dskip2
% 

verwandte Informationen