Fish-shell: Sonderfälle PATH/MANPATH/CDPATH sind seltsam; Wir brauchen eine allgemeinere Lösung wie zsh "gebundene" Variablen

Erstellt am 11. Dez. 2012  ·  52Kommentare  ·  Quelle: fish-shell/fish-shell

In expand.h :

/** Character for separating two array elements. We use 30, i.e. the ascii record separator since that seems logical. */
#define ARRAY_SEP 0x1e

/** String containing the character for separating two array elements */
#define ARRAY_SEP_STR L"\x1e"

Das führt zu:

xiaq<strong i="10">@blackie</strong> ~> set a (printf 'a\x1eb')
xiaq<strong i="11">@blackie</strong> ~> count $a
2
xiaq<strong i="12">@blackie</strong> ~> set a (printf 'a\x1fb')
xiaq<strong i="13">@blackie</strong> ~> count $a
1

Es ist klar, dass das Zeichen \x1e speziell als Elementtrennzeichen behandelt wird.

enhancement

Alle 52 Kommentare

Ist die Sorge, dass es keine Möglichkeit gibt, \x1e darzustellen? Oder denken Sie über architektonische Verbesserungen nach?

Ich denke, das Array-Trennzeichen wird hauptsächlich in persistenten Arrays an Orten verwendet, die nur Zeichenfolgen enthalten, wie universelle Variablen oder Umgebungsvariablen.

Am 12.12.2012 um 02:09 Uhr wurde "ridiculousfish" [email protected] veröffentlicht .

Ist die Sorge, dass es keine Möglichkeit gibt, \x1e darzustellen? Oder denkst du
über architektonische Verbesserungen?

Ich würde sagen, ich habe beide Bedenken im Auge. Denken Sie für Ersteres nur an a
Dateiname mit eingebettetem \x1e. POSIX sagt, dass alles außer \0 erlaubt ist
Dateinamen, also ist es durchaus möglich. Die Verwendung von \0 als Array-Trennzeichen kann sein
eine etwas bessere Wahl, aber das führt zu der zweiten Sorge - es ist
zerbrechlich und schlichtweg falsch.

Ich denke, der Array-Trenner wird hauptsächlich in persistenten Arrays an einigen Stellen verwendet
die nur Strings akzeptieren, wie universelle Variablen oder Umgebungsvariablen.

Wenn persistent "serialisiert" bedeutet, nein. Arrays werden immer in gespeichert
\x1e-getrennte Form. Exportierte Umgebungs-Arrays werden durch ":" verbunden. Sie
werden jedoch in universellen Variablen verwendet - die meiner Meinung nach implementiert werden sollten
mit richtigem Entkommen stattdessen.


Antworten Sie direkt auf diese E-Mail oder zeigen Sie sie auf GitHub an.

Wie wäre es, wenn Sie als Trennzeichen ein Zeichen für den privaten Bereich verwenden? In einigen Fällen verwendet Fish bereits einige davon.

@JanKanis Das ist nicht besser; Dies ist in Dateinamen (unter Berücksichtigung von Dateisystemen, die nicht-utf8, native Codierungen verwenden) und anderen Zeichenfolgen durchaus möglich.

Ich würde sagen, dass unter anderem "\0" eine _etwas_ bessere Wahl ist, da dies das einzige Zeichen ist, das UNIX in Dateinamen verbietet, aber es hat immer noch den schlechten Geruch für mich. Außerdem teilen und assemblieren wir bereits viele Arrays. Ich würde erwarten, dass die Implementierung echter Arrays sowohl zu einer besseren Architektur als auch zu weniger Code führt.

Fish verarbeitet bereits Zeichen für den privaten Gebrauch und ungültige Bytes, wenn es externe Zeichenfolgen in wchars codiert. Diese speziellen Werte werden Byte für Byte in einen bestimmten Satz von Zeichen für den privaten Gebrauch codiert, die Fisch bei der Ausgabe auch wieder decodiert, sodass die Verwendung eines anderen Zeichens für den privaten Gebrauch im Prinzip funktionieren könnte. Ich stimme jedoch zu, dass die Verwendung von echten Arrays viel besser ist. Es gibt eine Komplikation darin, dass die Kommunikation zwischen fish und fishd über einen Socket mit utf8-Strings erfolgt und dort fish (glaube ich) die Escape-Sequenz "\x1e" (anstelle eines 0x1e-Bytes) verwendet, um Array-Elemente zu trennen. Aber das könnte wahrscheinlich gelöst werden, indem zB eine private unbenutzte Escape-Sequenz verwendet wird.

Ich teile die Bedenken von xiaq, aber (für die praktischen) finde ich die implizite Aufteilung auf \n viel anstößiger:

a<strong i="6">@raspeball</strong> ~> count (printf 'a\x1eb')
1
a<strong i="7">@raspeball</strong> ~> count (printf 'a\nb')
2

Die (durch Zeilenumbrüche getrennte) Array-Interpretation der Subprozessausgabe sollte explizit und optional sein!

Aber das hat wahrscheinlich nichts mit der zugrunde liegenden Speicherung von Arrays zu tun …

@xiaq : Was ist falsch daran, \0 zu verwenden? xargs scheint es als seine "zuverlässige" Option zu verwenden.

Sie können \0 nicht in Umgebungsvariablen verwenden, was den Export von Arrays in untergeordnete Shells erschweren würde.

Ich migriere von zsh, wo ich diese Sequenz verwende, um die $LESS-env-Variable auf vernünftige Weise zu definieren, indem ich ihre Funktion "gebundene" Variablen verwende:

typeset -xT LESS less ' '
less=(
    --HILITE-UNREAD
    --LONG-PROMPT
)

Ich habe die vollständige Liste der Optionen der Kürze halber weggelassen. In zsh führt dies dazu, dass die Umgebungsvariable $LESS eine durch Leerzeichen getrennte Liste der Optionen im Array $less ist. Das Äquivalent in Fisch führt dazu, dass die Elemente durch das Datensatztrennzeichen (\x1e) getrennt werden. Trotz der Dokumentation, die besagt, dass die Elemente des Arrays durch Leerzeichen getrennt werden (modulo die speziellen Arrays wie PATH). Ich muss explizit eine Zuweisung vornehmen, die die Werte in eine einzelne Zeichenfolge interpoliert, um das erwartete Ergebnis zu erhalten:

set -x LESS --HILITE-UNREAD \
    --LONG-PROMPT
set LESS "$LESS"

Im Moment ist es mir egal, ob \x1e statt \x00 intern zum Serialisieren von Arrays verwendet wird. Es ist mir wichtig, dass exportierte Arrays ihre Elemente durch \x1e getrennt haben. Das ist einfach kaputt, falsch, fubar. Wähle dein Adjektiv. Es ist auch nicht mit der oben genannten Problemumgehung und dem dokumentierten Verhalten vereinbar. Dieses Problem sollte IMHO als Fehler gekennzeichnet werden.

PS, Nirgendwo in der Dokumentation wird die Verwendung des Datensatztrennzeichens (\x1e) erwähnt. Was ein weiteres Problem ist.

@krader1961 Danke, dass du das geteilt hast. Es gibt keine Standard-Unix-Konvention für listenartige Umgebungsvariablen - einige sind durch Doppelpunkte getrennt, andere durch Leerzeichen getrennt. fish verwendet \x1e, damit es seine eigenen Arrays unterscheiden kann.

Können Sie uns bitte auf die fehlerhafte Dokumentation hinweisen?

Wie denken Sie, dass Arrays exportiert werden - Doppelpunkte, Leerzeichen, Zeilenumbrüche, etwas anderes? Sollte Fish auch Umgebungsvariablen für diesen Charakter tokenisieren?

Es sieht so aus, als ob weniger durch Leerzeichen getrennte Argumente erwartet. Die wahrscheinlich einfachste Problemumgehung ist set -x LESS '--HILITE-UNREAD --LONG-PROMPT' usw.

Es gibt keinen Standard für listenähnliche Umgebungsvariablen, da sie per Definition eine willkürliche Folge von Bytes sind, die aus einem Schlüssel und einem Wert bestehen, die durch ein Gleichheitszeichen getrennt sind und durch ein Nullbyte abgeschlossen werden. Es müssen nicht einmal druckbare Zeichen sein. Die einzige allgemein akzeptierte Konvention für eine höhere Abstraktionsebene ist diejenige, die von der Funktion execlp() für die PATH-Umgebungsvariable festgelegt wurde.

Die Dokumentation ist insofern fehlerhaft, als sie nicht die Verwendung von \x1E, \036, 30 oder dem "Datensatztrennzeichen" erwähnt, um Elemente eines Arrays zu trennen, wenn eine Variable mit mehr als einem Element exportiert wird. Die Dokumentation sagt das aus

..., and array variables will be concatenated using the space character.

Das ist aus dem Abschnitt "Variable expansion" in http://fishshell.com/docs/current/index.html. Es ist vernünftig zu folgern, dass diese Aussage auch für exportierte Variablen gilt, die keine Sonderfälle sind, wie in den Abschnitten „Arrays“ und „Spezielle Variablen“ desselben Dokuments dokumentiert.

Ich habe das Gefühl, dass Fische env-Variablen nicht automatisch in eine Liste außerhalb der durch Doppelpunkte getrennten Sonderfall-Variablen wie PATH tokenisieren sollten. Es sollte jedoch ein robustes Mittel geben, mit dem ein Benutzer eine Variable in ein Array für ein beliebiges Zeichen tokenisieren kann.

Ohne einen Mechanismus zum Konfigurieren des zu verwendenden Zeichens auf einer Var-für-Var-Basis (wie der Befehl zsh "typeset -T") sollte ein Leerzeichen verwendet werden, wenn die Elemente des Arrays verkettet werden (wiederum mit Ausnahme der durch Doppelpunkte getrennten Sonderfälle vars ). Offensichtlich gilt dies nicht für private Datenspeicher wie die Speicherung universeller Variablen.

Schließlich konnte ich keine Verwendung in den Standard-Fischfunktionen finden, bei denen eine env-Variable verwendet wird, um ein Array mit mehr als einem Element an eine andere Funktion oder ein anderes Skript zu übergeben. Solche Anwendungsfälle können existieren, aber es sollte erfordern, dass die Skripte explizit bei der Serialisierung/Deserialisierung der Daten kooperieren, anstatt sich auf fish zu verlassen, um Arrays implizit aus Variablen zu rekonstruieren, deren Zeichenfolgen das Datensatztrennzeichen enthalten.

Vielen Dank für Ihre nachdenkliche Antwort. Der Abschnitt, den Sie über die Verkettung mit Leerzeichen zitiert haben, gilt speziell für Zeichenfolgen in doppelten Anführungszeichen. Wir sollten eine Diskussion darüber hinzufügen, was mit exportierten Arrays passiert.

Benutzer können Zeichenfolgen mit zB set SOMEPATH (string split : $SOMEPATH) tokenisieren.

Der Nachteil der Leerzeichenverkettung exportierter Variablen besteht darin, dass sie geändert werden, wenn fish rekursiv ausgeführt wird. Heute funktioniert das:

> set -x list 1 2 3
> count $list
3
> fish -c 'count $list'
3

Aber wenn wir mit Leerzeichen exportierten, würde dies 1 für den rekursiven Aufruf anzeigen. Wie Sie sagen, verlassen wir uns nicht darauf, aber vom Standpunkt der Konsistenz her ist es schön.

Vielen Dank für Ihre nachdenkliche Antwort.

Dem muss ich mich anschließen! Es ist immer wieder schön, einen frischen Blick auf die Dinge zu haben.

Für diejenigen, die neu in dieser Diskussion sind, denke ich, dass ich einige der Dinge einbringen muss, die damit zusammenhängen.

Was mir sofort in den Sinn kommt, ist die listify Whitelist , die in Ausgaben wie #2090 auftaucht.

Das bedeutet, dass $PATH, $CDPATH und $MANPATH als Listen/Arrays zum Fischen erscheinen, aber beim Export wieder mit ":" verbunden werden. Dann wird ein Fisch im Fisch sie wieder spalten. Dies funktioniert mit Doppelpunkten, nicht mit \x1e. Nach meinem Verständnis des Codes scheint es dies bei jedem Doppelpunkt zu tun, ohne die Möglichkeit zu entkommen, so dass es bei $PATH-Einträgen mit einem Doppelpunkt darin brechen könnte - was UNIX in Dateipfaden zulässt, obwohl es zumindest für $PATH gebrochen zu sein scheint . Dieses Schema wird zB auch für PYTHONPATH und GOPATH verwendet.

Ich hätte gerne etwas etwas expliziteres zum Aufteilen von Umgebungsvariablen als das implizite Always-Split-on-\x1e-außer-für-diese-drei-split-them-on-colon, weil dies eigentlich zwei verschiedene Schemata sind one und das Exportieren einer Liste wird derzeit immer alles außer Fisch verwirren.

Meine bevorzugte Lösung wäre eine Funktion wie splitenv var1 var2 var3 :

function splitenv --no-scope-shadowing
    set -e IFS # string split doesn't have superpowers, so unset IFS lest we split on both : and \n
    for arg in $argv
        set -q $arg; and set $arg (string split ":" $$arg)
    end
end

(Wenn string split Superkräfte hätte, wäre dies etwas einfacher)

Alle Listen würden dann beim Exportieren mit Doppelpunkten verbunden, sodass ein Benutzer sie explizit mit splitenv trennen kann (obwohl ich nicht fest auf eine Hilfsfunktion eingestellt bin, glaube ich, dass es gut ist, dies trivial zu machen etwas zu tun). Aus Gründen der Abwärtskompatibilität würde splitenv PATH CDPATH MANPATH beim Start ausgeführt werden. Wenn ein Benutzer es anders exportieren möchte, ist string join verfügbar.

All dies bedeutet, dass wir \x1e nicht mehr brauchen, wir haben ein Schema, das zumindest eine Kampfchance hat, von anderen Programmen verstanden zu werden, aber der (meiner Meinung nach ziemlich exotische) Fisch-in-Fisch wird jetzt zu fish -c 'splitenv list; count $list' .

Das Problem ist natürlich, dass das übliche Doppelpunkt-getrennte Listenschema, wie erwähnt, keine Möglichkeit hat, einen Doppelpunkt zu maskieren, und wenn wir einen hinzufügen wollten, hat string split kein "--unescaped". Option, nur Trennzeichen ohne Escapezeichen aufzuteilen.

Mache ich Sinn?

@faho Ich denke, diese Idee hat Verdienst. Der schlimmste Teil des alten Schemas war die implizite Aufteilung bei Doppelpunkten, wodurch Variablen verstümmelt wurden, die nicht aufgeteilt werden sollten. In Ihrer Idee ist dies (fast) immer explizit, daher denke ich, dass es ziemlich sicher ist.

In Bezug auf das Entkommen ist es gemäß dem von Ihnen gefundenen Link beabsichtigt, den Doppelpunkt in PATH nicht zu entkommen. Ich bezweifle, dass PYTHONPATH, CLASSPATH usw. in dieser Hinsicht konsistenter sind. Da Sie in diesen Pfaden keinen Doppelpunkt verwenden können, können wir wählen, ob wir ihn maskieren oder nicht; aber wenn wir einen Doppelpunkt maskieren, müssen wir Backslashes maskieren, und ich wette, Sie können einen Backslash in PATH verwenden. Wir brauchen vielleicht eine "Don't Escape" Whitelist (ugh).

Alternativ machen wir uns darüber keine Gedanken und lassen einfach einen beliebigen Doppelpunkt als Trennzeichen fungieren. Ich glaube, ich tendiere dazu, weil ich einfach und vertraut mit anderen Muscheln bin.

Wir stehen immer noch vor dem Problem, dass einige listenähnliche Variablen durch Leerzeichen und andere durch Doppelpunkte getrennt sind. Eine Möglichkeit ist, dass splitenv ein Trennzeichen akzeptiert, sich daran erinnert und es verwendet, um den Wert beim Export neu zu erstellen:

splitenv --on ' ' LESS
splitenv --on ':' PYTHONPATH

Diese Aufrufe spielen jetzt die doppelte Rolle, eine vorhandene Variable zu importieren und zu markieren, wie sie exportiert wird. Was denken Sie?

Gibt es auch eine Möglichkeit, dies zu tun, ohne config.fish zu bearbeiten? Vielleicht als Teil von universellen Variablen?

Wir stehen immer noch vor dem Problem, dass einige listenähnliche Variablen durch Leerzeichen und andere durch Doppelpunkte getrennt sind. Eine Möglichkeit besteht darin, dass splitenv ein Trennzeichen akzeptiert, sich daran erinnert und es verwendet, um den Wert beim Export neu zu erstellen:

Klingt gut. Obwohl es an diesem Punkt wahrscheinlich nicht helfen würde, splitenv zu einem Skript zu machen, da wir sowieso die Zusammenarbeit von der C++-Seite benötigen würden.

Diese Aufrufe spielen jetzt die doppelte Rolle, eine vorhandene Variable zu importieren und zu markieren, wie sie exportiert wird.

Es ist möglich, dass "splitenv" jetzt nicht mehr der perfekte Name ist (natürlich, als ich daran dachte :lach: ) - ich habe auch an "listify" gedacht.

Obwohl es mich nervt, dass ich mich nicht erinnern kann, wo wir schon einmal eine ähnliche Diskussion hatten - ich denke, ich muss die Probleme heute Abend noch einmal durchforsten.

Benutzer können Zeichenfolgen mit zB set SOMEPATH (string split : $SOMEPATH) tokenisieren.

Der Befehl string ist nirgendwo dokumentiert, was ich finden kann. Außerdem zeigt man string die Manpage string(3), die die Funktionen zur Manipulation von Strings auf BSD (und Mac OS X) dokumentiert.

Aber wenn wir mit Leerzeichen exportierten, würde dies 1 für den rekursiven Aufruf anzeigen. Wie Sie sagen, verlassen wir uns nicht darauf, aber vom Standpunkt der Konsistenz her ist es schön.

Dieses Verhalten ist jedoch überraschend. Ich bin bereit zu wetten, dass, wenn Sie 100 Leute fragen, was passiert, wenn eine Variable mit mehr als einem Element exportiert wird, 90 von ihnen sagen werden, dass die Werte mit Leerzeichen als Trennzeichen verkettet sind. Einige könnten sagen, dass Kommas oder andere Zeichen als Trennzeichen verwendet werden. Und die beiden Personen, die env ausgeführt haben, werden sagen, dass die Werte ohne Trennzeichen verkettet sind, da das Datensatztrennzeichen unsichtbar ist, wenn Sie die Ausgabe nicht durch etwas wie cat -evt filtern.

die in Ausgaben wie #2090 auftaucht

Es tut mir leid, aber ich sehe keinen Grund für die Beschwerde dieses Benutzers. Das Problem wird trivial umgangen, indem explizit getestet wird, ob MANPATH bereits gesetzt ist. Was Sie meiner Meinung nach angesichts der Semantik von führenden und nachgestellten Doppelpunkten auf jeden Fall tun müssen.

es könnte also bei $PATH-Einträgen mit einem darin enthaltenen Doppelpunkt brechen

Es ist mindestens dreißig Jahre zu spät, um das zu beheben. Wir sollten das Maskieren von Doppelpunkten (und damit des Escape-Zeichens) nicht implementieren, da dies ein nicht standardmäßiges Verhalten wäre. Bis vor kurzem habe ich mehr als 20 Jahre als UNIX-Supportspezialist gearbeitet. Ich habe noch nie gehört, dass sich jemand darüber beschwert hat, dass das Vorhandensein eines Doppelpunkts in einem Verzeichnis, das in $PATH oder eine ähnliche Variable eingebettet ist, ein Problem war.

Meine bevorzugte Lösung wäre eine Funktion wie splitenv var1 var2 var3

Das ist in Ordnung, obwohl nicht klar ist, warum die (undokumentierten) string split nicht ausreichen. Unabhängig davon, ob wir eine neue Funktion benötigen, sollten wir definitiv keine neuen Auto-Split-Env-Variablen hinzufügen. Die einzigen zwei, die häufig genug sind, um dieses Verhalten zu rechtfertigen, sind PATH und CDPATH (und MANPATH, da es sich bereits um einen Sonderfall handelt). Andere Variablen wie PYTHONPATH können von einem Benutzer explizit geteilt werden, wenn er dies für nützlich hält.

Allerdings sollte es sicherlich eine Möglichkeit geben, zu registrieren, dass eine bestimmte Variable (z. B. PYTHONPATH) ihre Elemente beim Export mit einem bestimmten Trennzeichen verkettet haben sollte. Der natürlichste Weg, dies zu tun, ist über eine neue Option für den set -Befehl. Zum Beispiel,

set -x -S ':' PYTHONPATH dir1 dir2 dir3

Dies würde sich nicht darauf auswirken, wie die var im universellen var-Datenspeicher gespeichert wird, wo das Datensatztrennzeichen weiterhin verwendet würde, und es würde automatisch geteilt, wenn es aus diesem Datenspeicher geladen wird. Zu bestimmen ist, ob das eingetragene Trennzeichen für den Export auch die String-Interpolation beeinflussen soll. Mein Gefühl ist, dass es sollte. Das heißt, wenn der obige "set"-Befehl ausgeführt wird, dann ein nachfolgender

echo "PYTHONPATH is $PYTHONPATH"

sollte anstelle eines Leerzeichens einen Doppelpunkt verwenden, um die Werte von PYTHONPATH zu verketten. Das Standardtrennzeichen ist ein Leerzeichen, um die vorhandene Semantik beizubehalten und die Überraschung für den Benutzer zu minimieren. Beachten Sie, dass die Sonderfall-Variablen wie PATH in diesem Beispiel auch einen Doppelpunkt verwenden würden. Was mit dem aktuellen Verhalten nicht kompatibel ist, aber mit der neuen Semantik konsistent und weniger überraschend ist. Mit anderen Worten, warum werden die Elemente von $PATH in der exportierten Umgebung durch Doppelpunkte getrennt, aber in der Ausgabe von Leerzeichen?

echo "PATH is $PATH"

Der String-Befehl ist nirgendwo dokumentiert, was ich finden kann. Außerdem zeigt man string die man-Seite string(3) an, die die String-Manipulationsfunktionen auf BSD (und Mac OS X) dokumentiert.

Ruhig Tiger. Es ist in den Entwicklungsversionen - siehe https://github.com/fish-shell/fish-shell/blob/master/doc_src/string.txt

Das ist in Ordnung, obwohl nicht klar ist, warum die (undokumentierte) Saitenaufteilung nicht ausreicht.

Meine ursprüngliche Idee war, dass es sich um eine Komfortfunktion handelt, sodass diese Operation völlig trivial wird. Mit dem Vorschlag von @ridiculousfish wird es etwas mehr und passt eine Art Speicher an, sodass die Variable beim Exportieren auch mit diesem Zeichen verbunden wird. string split ist nur ein Befehl, der einen String aufteilt – im Grunde unsere Version von cut .

Am natürlichsten geht das über eine neue Option für den set-Befehl.

Das ist eine weitere Option, obwohl ich von der Semantik nicht ganz überzeugt bin. ZB set -S ':' PYTHONPATH . Würde das PYTHONPATH auf die leere Liste setzen oder würde es nur das vorhandene PYTHONPATH aufteilen? Bisher haben alle Set-Optionen das Erste getan, also müssten Sie set -S ':' PYTHONPATH $PYTHONPATH tun. Oder wir würden es _nicht_ machen lassen und Inkonsistenzen innerhalb desselben Tools haben.

Mit anderen Worten, warum werden die Elemente von $PATH in der exportierten Umgebung durch Doppelpunkte getrennt, aber Leerzeichen in der Ausgabe von echo "PATH is $PATH"

Das ist eigentlich eine gute Frage. Natürlich würden Sie nicht erwarten, dass das Trennzeichen beispielsweise in for p in $PATH; echo $p; end auftaucht, aber das Verbinden mit dem Trennzeichen pro Variable könnte das Richtige sein. Natürlich gibt es string join , um es manuell zu machen.

Dieses Verhalten ist jedoch überraschend. Ich bin bereit zu wetten, dass, wenn Sie 100 Leute fragen, was passiert, wenn eine Variable mit mehr als einem Element exportiert wird, 90 von ihnen sagen werden, dass die Werte mit Leerzeichen als Trennzeichen verkettet sind.

Es gibt ein allgemeines Problem mit Design-by-Survey und Fish. Weil die befragten Personen häufig Kenntnisse über bash (und in geringerem Maße andere POSIXy-Shells) haben, während die eigentliche Idee von fish darin besteht, etwas _besseres_ zu machen, indem man zumindest einen Teil von POSIX aufgibt.

Das soll nicht heißen, dass es völlig wertlos ist, es ist nur etwas, das man im Hinterkopf behalten sollte - wenn wir uns an diese Art von Ideen halten würden, hätten wir das wortspaltende Verhalten und das if-fi von bash.

Würde set -S ':' PYTHONPATH PYTHONPATH auf die leere Liste setzen oder würde es einfach den bestehenden PYTHONPATH teilen?

Es würde es auf eine leere Liste setzen. Wenn der Benutzer den vorhandenen Wert beibehalten möchte, muss er ihn explizit einschließen (siehe unten).

Wir verfügen bereits über alle erforderlichen Funktionen mit Ausnahme eines Mittels zum Konfigurieren des Zeichens (oder der leeren Zeichenfolge), das verwendet werden soll, wenn Array-Elemente einer bestimmten Variable für den Export oder die Interpolation verkettet werden. Wenn jemand eine Variable wie PYTHONPATH manipulieren möchte, kann er sie entweder als einfachen String behandeln:

set PYTHONPATH "/a/new/dir:$PYTHONPATH"

Oder sie können es als Array behandeln:

set -S ":" PYTHONPATH /a/new/dir (string split ":" $PYTHONPATH)

Beachten Sie, dass mein Vorschlag, bei der Interpolation in eine Zeichenfolge das Split/Concatenation-Zeichen anstelle eines Leerzeichens zu verwenden, ein konsistentes Verhalten bietet, unabhängig davon, ob der Benutzer die Variable in ein Array aufteilt oder nicht.

Ich schlage definitiv kein Design by Committee vor. Auf diesem Weg liegen Wahnsinn und Bogosities wie zsh. Ich weise nur darauf hin, dass es die beste Wahl ist, wenn man zwei oder mehr Optionen ohne einen anderen Grund hat, eine der anderen zu wählen, dann die Option zu wählen, die einen Benutzer der Shell am wenigsten überrascht. Das ist auch der Grund, warum ich (im Moment) dagegen bin, neue Befehle oder Verhaltensweisen wie das automatische Aufteilen von Variablen (natürlich außer PATH und CDPATH) einzuführen. Dies ist die Art von Dingen, die selten und normalerweise nur in config.fish und einigen spezialisierten Funktionen wie dem "activate"-Skript von Anaconda durchgeführt werden. Und der Weg, um letzteres dazu zu bringen, sich korrekt zu verhalten, unabhängig davon, ob der Benutzer die var in seiner config.fish bereits in ein Array aufgeteilt hat oder nicht, besteht darin, sie immer als Zeichenfolge zu behandeln, die aufgeteilt werden muss. Wenn zum Beispiel PYTHONPATH geändert werden müsste, könnte es etwa so aussehen:

# Hypothetical snippet from the Anaconda activate script.
if test (count PYTHONPATH) -gt 1
    set -S ':' PYTHONPATH /activated/python/tree $PYTHONPATH
else
    set PYTHONPATH "/activated/python/tree:$PYTHONPATH"
end

Oder einfacher gesagt

# Hypothetical snippet from the Anaconda activate script.
set -S ':' PYTHONPATH /activated/python/tree (string split ':' $PYTHONPATH)

Ja, das verwandelt möglicherweise eine einfache Zeichenfolge in ein Array. Aber mit meiner Regel, dass das durch den Schalter -S angegebene Zeichen beim Exportieren und Interpolieren verwendet wird, sollte diese Konvertierung in ein Array in der Praxis keine Rolle spielen. Es gibt jedoch einen Eckfall. Was passiert, wenn der Benutzer die var in seiner config.fish nicht explizit in ein Array konvertiert hat und er dann so etwas wie das obige hypothetische Skript ausführt. Die Variable wird möglicherweise zu einem Array mit mehreren Elementen, was bedeutet, dass dies später der Fall ist

for elem in $PYTHONPATH
   echo $elem
end

Dadurch wird der Körper der for-Schleife nicht nur einmal mit dem Wert in Form von durch Doppelpunkte getrennten Verzeichnissen ausgeführt, wie der Benutzer vielleicht erwarten würde, da er sich der Aufteilung durch das hypothetische „activate“-Skript nicht bewusst war. Ich denke, wir können damit leben, da es für einen Benutzer pervers wäre, so etwas zu tun.

tl; dr Ich denke, Listen sollten sich an ihr Trennzeichen "merken" und unten ist der Grund dafür.


Ich stimme vielen der meisten der oben genannten zu. Eine Sache, die jedoch immer noch mühsam erscheint, ist, dass die obigen Befehle immer noch übermäßig ausführlich erscheinen; dh manchmal ist es einfacher, einige dieser Befehle in einfachem Englisch zu beschreiben.

Als Beispiel (und ich konzentriere mich nicht so sehr auf die Länge als auf die Anzahl der wiederholten Dinge):

  • Fisch: set -S ':' PYTHONPATH /activated/python/tree (string split ':' $PYTHONPATH)
  • Deutsch: " /activated/python/tree an PYTHONPATH anhängen ( : -delimited`)"

Hier gibt es zwei wiederkehrende Dinge: PYTHONPATH und das Trennzeichen : . Dass PYTHONPATH wiederholt werden sollte, ist wohl aus zwei Gründen in Ordnung, und keiner dieser beiden Gründe trifft auf das Trennzeichen zu.

  1. Es ist nicht schwer zu verstehen, was los ist, wenn jemand set PYTHONPATH /activated/python/tree $PYTHONPATH sagt, weil dies sehr ähnlich ist wie i = 2 + i , was ein sehr bekanntes Konzept/Idiom ist. (Aber wir haben immer noch Abkürzungen wie += , weshalb ich unten das Flag --append vorschlage.) Auf der anderen Seite denken die Leute nicht daran, sie aufzuteilen, wenn sie an das Anhängen an eine Liste denken und Verbinden mit einem Trennzeichen. Sie denken nicht daran, die gesamte Liste in ein anderes Format zu konvertieren, die eigentliche Operation damit durchzuführen und sie zurückzusetzen. Ihrer Meinung nach lesen sie das Trennzeichen natürlich als Trennzeichen, anstatt es in ein "internes" oder "bevorzugtes" Trennzeichen zu ändern.
  2. Die Verwendung eines einfachen set -Befehls zum Anhängen von Speichern erspart das Hinzufügen eines weiteren Befehls zum Verbinden zweier verschiedener Listen. Andererseits ist das Konvertieren von einem Trennzeichen in ein anderes etwas, das der Benutzer im Idealfall niemals manuell durchführen soll, hauptsächlich aus dem oben genannten Grund.

Im Gegensatz dazu schlage ich eine andere Möglichkeit vor, das Trennzeichen auf Listen anzugeben: Verknüpfen Sie es auf unbestimmte Zeit mit der Liste. Das obige Beispiel könnte also wie folgt durchgeführt werden:

# Changes the delimiter for this list. This might be done in some global config file for common lists as this one.
set -S ':' --no-modify PYTHONPATH
# or, workaround if you don't want to add extra options to set:
set -S ':' PYTHONPATH $PYTHONPATH

# The actual append operation
set --prepend PYTHONPATH /activated/python/tree
# or, workaround if you don't want to add extra options to set:
set PYTHONPATH /activated/python/tree $PYTHONPATH

Implikationen/Folgefragen/etc:

  1. Dies ist ziemlich kompatibel mit dem aktuellen Vorschlag. Hier sind die erforderlichen Änderungen:

    • Machen Sie das Trennzeichen (möglicherweise durch Verwendung einer anderen Variablen als __fish_sep_PYTHONPATH )

    • (optional) Fügen Sie ein Flag hinzu, das ich gerade --no-modify , das Fisch anweist, das Trennzeichen einer Liste zu ändern, ohne ihren Inhalt zu ändern. Fügen Sie möglicherweise auch die Flags --append und --prepend wegen Grund (1) oben hinzu. Wie auch immer, dieser ist nicht erforderlich, wie der obige Workaround zeigt, à la wie das Anhängen und Voranstellen in Fish heute gemacht wird.

  2. Bei Fischen müssen Listen zumindest wie Bürger erster Klasse _behandelt_ werden. Dies bedeutet, dass das Ändern des Trennzeichens die Zeichenfolgendarstellung ändern sollte, nicht die Listendarstellung (es sei denn, das Trennzeichen ist in einem der Elemente vorhanden, in diesem Fall ist eine Aufteilung dort unvermeidlich). Wenn Sie beispielsweise die Trennzeichen von , in : ändern, sollte ["0:1", "2"] zu ["0", "1", "2"] werden und nicht zu ["0", "1,2"] (was genau das ist, was würde passieren, wenn Sie einfach das Trennzeichen ändern, ohne die Zeichenfolge zu ändern, die die Liste unterstützt). Dieses Verhalten sollte die Kompatibilität mit dem aktuellen Verhalten und der Tatsache maximieren, dass derzeit ein unveränderliches Standardtrennzeichen vorhanden ist.

Hier ist die Quintessenz:

  • Dies beinhaltet viel weniger Token und fast nichts wird wiederholt.
  • Dies entspricht dem mentalen Modell, das viele Benutzer haben. Benutzer denken in diesen Begriffen: "voranstellen", "Trennzeichen setzen", "nicht ändern".
  • Dies scheint der einzig richtige Weg zu sein, um diese Aufgabe zu erledigen (der alte Weg sieht jetzt besonders ungeschickt aus), und daher zerstören diese Hinzufügungen die Orthogonalität nicht.
set --no-modify -S : PYTHONPATH
set --prepend PYTHONPATH /activated/python/tree

Vielen Dank, @szhu , für den ausführlichen Kommentar zu meinem Vorschlag. Es gibt jedoch viele Probleme mit Ihrer vorgeschlagenen Lösung. Beispielsweise ändert das Hinzufügen der Option --no-modify die Variable tatsächlich, indem sie in eine Liste umgewandelt wird, und modifiziert somit die Variable. Ich lehne zwar fast alle Elemente Ihres Vorschlags ab, ließ mich aber über eine einfachere Lösung nachdenken, die die meisten, wenn nicht alle Ihrer Punkte ansprechen würde. Vielleicht sollte es einen Mechanismus geben, um fish mitzuteilen, dass eine gegebene env-Variable immer automatisch geteilt und auf einem gegebenen Token wiederhergestellt werden soll (z. B. ":" oder " "). Dies könnte als automatische Array-Bezeichnung bezeichnet werden, und bei der Ausführung würde jeder vorhandene Wert sofort geteilt, wenn es sich nicht bereits um ein Array handelt.

Eine neue Option könnte dem Set- Befehl hinzugefügt werden, um dieses Verhalten zu aktivieren. Ich befürchte jedoch, dass dies mehrdeutig ist und als Definition einer Variablen ohne Wert interpretiert werden könnte. Wäre das Hinzufügen einer Token-Option -A zum set- Befehl eindeutig? Zum Beispiel:

set -x -A ':' PYTHONPATH

Vermutlich würde dies sofort jede vorhandene PYTHONPATH-env-Variable in ein Array konvertieren, nachdem sie auf einen Doppelpunkt aufgeteilt wurde. Umgekehrt würde dies dazu führen, dass die Werte beim Exportieren oder Interpolieren in einen String mit einem Doppelpunkt verkettet werden. Auch wenn PYTHONPATH zum Zeitpunkt der Ausführung dieses Befehls nicht existierte, würde die Auto-Array-Spezifikation gespeichert und nachfolgende Verwendungen wären davon betroffen. Zum Beispiel würde dies offensichtlich ein Array erstellen:

set PYTHONPATH /a/path /b/path /c:/d/path

Aber was ist mit dem letzten Argument? Soll es automatisch in zwei Token aufgeteilt werden?

Beachten Sie, dass dieses Verhalten nur für exportierte Variablen gelten sollte und andernfalls ein Fehler ausgelöst würde. Es gibt auch einige Eckfälle, die beschrieben werden müssen. Was ist beispielsweise, wenn die ursprüngliche Auto-Split-Deklaration Werte wie in diesem Beispiel enthält:

set -x -A ':' PYTHONPATH 'hello:goodbye' $PYTHONPATH

Sollten diese Werte auf dem Auto-Split-Token aufgeteilt werden? Oder sollte es zu einem Fehler führen und erfordern, dass der Wert in einer separaten Anweisung geändert wird? Unabhängig davon, welche Syntax gewählt wird, bleibt die Frage, was mit Werten zu tun ist, die das Auto-Split-Token enthalten. Der Teufel steckt im Detail. Das heißt, es könnte andere Auswirkungen dieses Vorschlags geben, an die ich nicht gedacht habe. Mein ursprünglicher Vorschlag mit einer ausführlicheren Syntax vermeidet diese Probleme, soweit ich das beurteilen kann.

@krader1961 , danke für deine Antwort. Sie scheinen jedoch zu denken, dass ich Variablen von Zeichenfolgen in Listen umwandle. Ich glaube, Sie missverstehen ein wichtiges Konzept in fish: Jede Variable ist eine Liste von Strings . Die Variablen, die wie Strings aussehen, sind eigentlich Listen der Länge 1. fish behandelt sie nicht anders als Listen der Länge 0 oder 2 oder jeder anderen Länge.

Beachten Sie auch, dass sich zwar die zugrunde liegende Zeichenfolge, die zum Umgeben von Umgebungsvariablen verwendet wird, ändern kann, wenn Sie Trennzeichen ändern, eine der Stärken von Fisch ist jedoch, dass der Benutzer normalerweise überhaupt nicht über Trennzeichen nachdenken muss. Aus diesem Grund empfehle ich, dass die Option -S lediglich angibt, wie diese Liste in einen String umgewandelt werden soll, wenn sie _nach draußen_ exportiert wird. -S sollte die In-Fish-Listendarstellung nicht ändern (außer in Fällen, in denen es unmöglich ist, diese Liste mit dem Zieltrennzeichen darzustellen).

Übrigens, hier ist ein Beispiel, das zeigt, wie sauber mein Vorschlag ist. Hier ist Code zum Konvertieren einer Variablen $L zurück in das Standardtrennzeichen von \x1e . Es wird absolut keine Auswirkung auf irgendeine Variable (jeden Bereich, jede Anzahl von Elementen) haben, die heute in Fish erstellt werden kann.

set -S \x1e L $L

Eine weitere Sache: Die --no-modify Familie von Argumenten sind nur Abkürzungen. Hier sind ihre Äquivalente:

| Verknüpfung | Äquivalent |
| --- | --- |
| set [other args] --no-modify L | set [other args] L $L |
| set [other args] --prepend L $TOADD... | set [other args] L $TOADD... $L |
| set [other args] --append L $TOADD... | set [other args] L $L $TOADD... |

(Ich habe das Folgende schon früher gesagt, aber ich denke, ich kann es jetzt besser erklären.) Durch die Betonung, wie "dumm" diese drei Argumente sind, fragen sich einige vielleicht, ob sie überhaupt benötigt werden. Man kann anführen, dass Fisch ein Gestaltungsprinzip der Orthogonalität hat . Wenn alle Dinge orthogonal sind, bedeutet dies, dass es für jede große Aufgabe, die Sie erledigen möchten, offensichtlich sein sollte, welche Funktionen Sie auswählen müssen, um diese Aufgabe zu erledigen – es sollte nur einen richtigen Weg geben, dies zu tun. Hier füge ich in der Tat eine weitere Möglichkeit hinzu, um einer Liste eine Änderung voranzustellen/anzuhängen/zu verhindern, aber das liegt nur daran, dass ich denke, dass die ersetzten Äquivalente unnötig ausführlich sind; Sie sollten nicht die richtigen Methoden zum Anhängen von Änderungslisten sein. Eine Möglichkeit, sich davon zu überzeugen, besteht darin, darüber nachzudenken, wie Sie sich das Anhängen an eine Liste vorstellen. Sie denken wahrscheinlich „ $TOADD an $L anhängen“ statt „ $L an $L $TOADD setzen“.

Lassen Sie mich wissen, was Sie denken und ob dies ein überzeugenderes Argument für meinen Vorschlag darstellt. (Außerdem kommt es ziemlich häufig vor, dass ich Dinge missverstehe, also zögern Sie nicht, mich zu korrigieren.)

@szhu Ich bin mir ziemlich bewusst, dass alle Variablen in Fisch Listen mit null, einem oder mehreren Werten sind. Sie haben anscheinend auch meine früheren Kommentare nicht gelesen, in denen ich klar feststelle, dass das zugehörige Trennzeichen die interne Darstellung oder die Art und Weise, wie die Werte im universellen Datenspeicher gespeichert werden (außer dem Speichern des Trennzeichens), nicht beeinflussen sollte. Sie sind auch nicht auf meine vorherigen Punkte eingegangen. Betrachten Sie Ihr letztes Beispiel:

set -S \x1e L $L

Was soll das tun, wenn L bereits zwei oder mehr Werte enthält? Vermutlich nichts anderes, als das zugehörige Trennzeichen zu ändern. Wäre das $L- Argument in diesem Fall optional? Oder sollte es zuerst das vorhandene Array in eine einfache Zeichenfolge konvertieren (vermutlich unter Verwendung des vorhandenen Trennzeichens verketten) und dann diese Zeichenfolge auf das neue Trennzeichen aufteilen? Wie ich bereits sagte, steckt der Teufel im Detail.

Letztendlich werden die etablierten Designer und Betreuer entscheiden, ob Ihre --no-modify Funktionsfamilie hinzugefügt werden soll oder nicht, aber ich stimme mit Nein, da sie meiner Meinung nach im Verhältnis zu ihren Kosten keinen ausreichenden Mehrwert bieten.

Entschuldigung, dieser Thread ist lang, ich muss Ihre Bestätigung oben verpasst haben; Gut zu wissen, dass wir auf derselben Seite sind! Ich glaube, ich habe auch die meisten Ihrer Bedenken oben angesprochen, aber nicht alle. Ich werde im Folgenden speziell auf jedes Ihrer Anliegen eingehen.


1. Ist $L in set -S \x1e L $L $ optional?

Das bestehende Verhalten von set wird sich nicht ändern. Beim aktuellen Verhalten ändert set L $L L nicht und set L macht L zu einer leeren Liste. Dasselbe gilt für set -S \x1e L $L und set -S \x1e L .

1.1 Scheint set -S \x1e L $L nicht zu ausführlich zu sein, nur um das Trennzeichen zu ändern?

Leicht. Deshalb schlage ich die Option --no-modify als Abkürzung dafür vor.

Aber mein Plan wird nicht auseinanderfallen, wenn es diese Abkürzung nicht gibt. Wir beschäftigen uns bereits täglich damit, wenn wir Listen anhängen: set PATH ~/.bin $PATH . Aus demselben Grund schlage ich auch --prepend und --append vor.

2. Wie würde der Konvertierungsprozess ablaufen?

Nehmen wir an, unser altes Trennzeichen ist \x1e und unser neues : , und wir haben eine Fischliste ["hello", "world"] (exportiert als hello\x1eworld ). Es gibt zwei grundlegende Möglichkeiten zur Konvertierung (" Konvertierungsoptionen "):

  1. Verwenden Sie ["hello", "world"] und konvertieren Sie es in ["hello", "world"] (exportiert als hello,world )
    Vorteil: Die Listendarstellung ändert sich nicht.
  2. Verwenden Sie hello\x1eworld und konvertieren Sie es in ["hello\x1eworld"] (exportiert als hello\x1eworld )
    Vorteil: Die exportierte Wertdarstellung ändert sich nicht.

Beachten Sie, dass dies aus Sicht der Benutzeroberfläche und nicht aus Sicht der Implementierung erfolgt. wir sprechen darüber, wie es dem Benutzer erscheint. Ich werde die Implementierung in der nächsten Frage behandeln. _Hinweis: Der Rest dieser Antwort ist neu, was ich oben nicht angesprochen habe, aufgrund Ihrer Fragen. Danke!_

Im Fisch. Erstens, wenn wir ausschließlich mit Fisch arbeiten, sind Listen erstklassig und Sie sollten sich nie um Trennzeichen kümmern müssen, und daher sind beide nicht erforderlich. (Auch hier ist „sollte“ aus der Sicht eines Benutzers, als Entwickler liegt es in unserer Verantwortung, dies wahr zu machen.)

Ändern des Exportformats von var. Daher ist der einzige Grund, warum ein Benutzer Trennzeichen ändern muss, die exportierte Zeichenfolge für Programme zu ändern, die Umgebungsvariablen lesen. Für Listen, die in fish erstellt werden, werden wir definitiv Konvertierungsoption 1 verwenden, da die Bedeutung der Variablen als Liste wichtig und klar definiert ist, sodass wir die Listendarstellung beibehalten müssen.

Ändern des Importformats von var. Für Umgebungsvariablen wie PATH , die anfänglich außerhalb von fish erstellt werden, müssen wir für eine Liste, die bereits ein Trennzeichen hat, fish mitteilen, was dieses Trennzeichen ist. Dazu können wir Konvertierungsoption 2 verwenden.

2.1 Wie würde dies umgesetzt werden?

Fish, auch wenn der Benutzer dies nicht wissen muss, speichert fish Listen tatsächlich als Strings. Die Variable x wird als hello\x1eworld gespeichert. Unter meinem Vorschlag gäbe es eine weitere Variable, __fish_delimiter_x , die das Trennzeichen der Variablen x angibt. Es existiert derzeit nicht und daher verwenden wir das Standardtrennzeichen \x1e .

Für Konvertierungsoption 1:

  1. Teilen Sie die Variable am alten Trennzeichen, was zu einer echten Liste in der Implementierungssprache (C++) führt.
  2. Verbinden Sie die Liste mit dem neuen Trennzeichen, was zu einer neuen Zeichenfolge führt.
  3. Speichern Sie das neue Trennzeichen in __fish_delimiter_x .

Für Konvertierungsoption 1 eine äquivalente Implementierung:

  1. Ersetzen Sie in der Variablen alle Vorkommen des alten Trennzeichens durch das neue.
  2. Speichern Sie das neue Trennzeichen in __fish_delimiter_x .

Für Konvertierungsoption 2:

  1. Speichern Sie das neue Trennzeichen in __fish_delimiter_x .

2.2 Wenn wir beide Konvertierungsoptionen benötigen, wie würde der Benutzer angeben, welche verwendet werden soll?

Vielleicht haben wir zwei Optionen: -D oder --convert-delimiter für Option 1 und -d oder --set-delimiter für Option 2.

2.3 Brauchen wir wirklich beide Optionen?

Unter aktuellen Fischen gehen wir davon aus, dass wir außerhalb von Fischen keine \x1e in freier Wildbahn sehen werden. Wenn wir dies als Standardtrennzeichen beibehalten und diese Annahme beibehalten, reicht die Konvertierungsoption 1 aus, um das Trennzeichen sowohl zu konvertieren als auch festzulegen, und wir benötigen keine Konvertierungsoption 2 . (Eine einfache Möglichkeit, sich davon zu überzeugen, besteht darin, zu erkennen, dass, wenn die Annahme zutrifft, beim Konvertieren von extern erstellten Listen der Schritt der Konvertierungsoption 1 "alle Vorkommen des alten Trennzeichens durch das neue ersetzen" nichts bewirkt und die gesamte Konvertierung reduziert zu Konvertierungsoption 2.)


@ridiculousfish , ich würde mich auch über Ihr Feedback dazu freuen, insbesondere in Bezug auf die Benutzeroberfläche und die Implementierungsdetails. Danke!

Es scheint, dass es hier zwei Probleme gibt. Reden wir einfach über den ersten?

+1 für echtes Array

Braucht man diesen Separator-Trick wirklich für Fisch? Ping #627

Betrachten Sie dies im Lichte meines Fixes für Problem Nr. 2106, bei dem ich bemerkte, dass es zwei inkompatible Möglichkeiten gab, die Zeichenfolgendarstellung für Variablenwerte in Arrays zu konvertieren. Eines davon ließ fälschlicherweise leere Elemente aus. Das Kernproblem ist, dass class env_var_t auf wcstring und nicht auf einem Vektor von wcstring basiert. Ob sich die Mühe lohnt, das zu ändern, steht zur Debatte.

Wenn Sie diese Ausgabe verfolgen, empfehle ich Ihnen, PR #4082 anzusehen und vielleicht zu testen. Ich habe entschieden, dass der beste Weg, dies anzugehen, "gebundene" Variablen sind, die der gleichnamigen Funktion in zsh ähneln.

Es scheint, als ob die Fragen rund um diese durch Doppelpunkte exportierten Listen und welche Envvars in diese Whitelist aufgenommen werden sollten, noch unentschieden sind. Wie ist der aktuelle Stand in dieser Angelegenheit? Können wir auf eine endgültige Lösung dieses Themas hoffen? Gerade heute laufe ich wieder in die Falle, dass LD_LIBRARY_PATH nicht in der Whitelist ist...

Zusammenfassend: Unix-Umgebungsvariablen sind Zeichenfolgen, daher müssen Array-ähnliche Umgebungsvariablen ein Trennzeichen verwenden. Die meisten verwenden Doppelpunkte ($PATH); obwohl nicht alle ($LESS). Wir würden gerne einfach Doppelpunkte verwenden, um alle Arrays beim Import/Export zu trennen (und in der Tat hat Fisch früher so funktioniert); Das Problem ist, dass einige flache Variablen Doppelpunkte enthalten ($DISPLAY, $SSH_CONNECTION).

Das Ziel ist, dass begrenzte Variablen mit der Array-Unterstützung von Fish auf natürliche Weise funktionieren. @szhu schlug vor, set zu verbessern, um ein Trennzeichen zu verfolgen, aber meiner Meinung nach ist die Verbesserung von set der falsche Ort, um dies anzuhängen:

  • Lästige Interaktion zwischen dem Setzen der Variable und dem Setzen ihres Trennzeichens (motivierend --no-modify ).
  • Knifflige Fragen dazu, wie Trennzeichen mit dem Gültigkeitsbereich von Variablen interagieren.
  • Probleme rund um universelle Variablen. Wir müssten uvars beibringen, sich das Trennzeichen zu merken, und auch etwa --no-modify , da es keine Möglichkeit gibt, eine Variable mit uvars auf ihren aktuellen Wert zu setzen.

Bei der Überprüfung bevorzuge ich die Splitenv - Idee von @faho. splitenv name würde die vorhandene Variable auf Doppelpunkte aufteilen, das war's. Es ist wunderbar einfach. Variablen, die keine Doppelpunkte verwenden, sind so selten, dass wir keine spezielle Unterstützung für sie benötigen.

Der Nachteil ist, dass Fisch exportierte Arrays als eine durch Doppelpunkte getrennte Zeichenfolge wieder importiert werden würden; in der Praxis denke ich, dass dies selten sein wird.

Wir sollten Benutzern diese splitenv Komplikation nicht zufügen, wenn wir sie vermeiden können. Ich möchte also noch einen Schritt weiter gehen und die Doppelpunkt-Whitelist auf alle Umgebungsvariablen erweitern, deren Name auf PATH endet , zB LD_LIBRARY_PATH, PYTHONPATH usw. In der Praxis sollte dies fast immer das Richtige tun; Jeder, der davon gebissen wird, kann mit string join den Wert erhöhen.

Also, was ich vorschlage (wirklich Fahos Vorschlag):

  • Exportieren Sie alle Arrays mit Doppelpunkten; kein ASCII-Datensatztrennzeichen mehr.
  • Implementieren Sie eine splitenv -Funktion, die eine Variable nach Doppelpunkten aufteilt. Dies kann in Fischschrift geschrieben werden.
  • Erweitern Sie die durch Doppelpunkte getrennte Whitelist um alle Variablen, die mit PATH enden.

Ich glaube, dass dies die meisten Probleme im Zusammenhang mit durch Doppelpunkte getrennten Arrays auf minimalistische und kompatible Weise lösen wird.

bezüglich der splitenv-Idee:

Angenommen, ich wollte, dass Fish eine Liste exportiert, deren Elemente Doppelpunkte enthalten, zum Beispiel: ["item1", "item:2"] . (Ich glaube nicht, dass dies ein seltenes Ereignis ist, insbesondere wenn Arrays zum Speichern von Benutzereingaben verwendet werden.)

Wird die Liste als item1:item:2 exportiert? In diesem Fall kann die ursprüngliche Liste nach dem Export nicht wiederhergestellt werden.

Außerdem fühlt es sich falsch an, eine unveränderliche Whitelist für Variablen zu haben, obwohl es sich weniger falsch anfühlt, wenn die Whitelist *?PATH ist. (Das war ein weiterer Grund für meinen Vorschlag, das Trennzeichen als Variable zu speichern – die Whitelist kann geändert werden, indem eine Variable gesetzt wird.)

@szhu Du hast recht. Exportierte-Listen-können-keine-Doppelpunkte enthalten ist ein Problem, unter dem Unix bereits leidet :

Seit \

Daher fühle ich mich nicht schlecht, wenn ich dieselbe Einschränkung für Fische einführe (nur für exportierte Variablen).

Dieses Problem tritt auch nur auf, wenn ein Array in eine rekursiv aufgerufene Fischinstanz exportiert wird, was meiner Meinung nach selten sein wird. Wenn dies üblich ist, könnten wir entweder Sidecar-Daten in einer anderen Variablen anhängen oder ein anderes Array-Trennzeichen verwenden, wenn wir fish rekursiv aufrufen. Meine Vermutung ist, dass wir nicht so weit gehen müssen.

Ich stimme zu, dass der Grenzfall, in dem der Vorschlag nicht gut funktioniert, nicht sehr häufig vorkommt, aber ich fürchte, es wäre wirklich schlimm, wenn Leute darauf stoßen würden.

Hier ist ein Beispiel, das nur teilweise erfunden ist:

set -x TEST color:red 
set -x TEST2 color:red font:serif
set -x TEST_PATH color:red 
set -x TEST2_PATH color:red font:serif
exec fish
echo $TEST #=> color:red
echo $TEST2 #=> color:red:font:serif
echo $TEST_PATH #=> color red 
echo $TEST2_PATH #=> color red font serif

Ich kann mir vorstellen, dass viele neue Benutzer verwirrt sind, nachdem sie das oben Gesagte beobachtet haben.

Wesentlich angenehmer fände ich folgendes Verhalten:

set -x TEST color:red 
set -x TEST2 color:red font:serif
set -x TEST_PATH color:red 
set -x TEST2_PATH color:red font:serif
exec fish
echo $TEST # color:red
echo $TEST2 # color:red font:serif
echo $TEST_PATH #=> color:red 
echo $TEST2_PATH #=> color:red font:serif

Ich hätte gerne Ihre Meinung und die der Community zu diesem Thema.

Warum nicht vorhandene Doppelpunkte entkommen? Das würde die Unterscheidung wahren.

Flucht macht für mich Sinn.

Könnte es immer noch verwirrend sein, dass nicht erinnert wird, ob eine Variable ein Array ist?

set -x TEST2 color:red font:serif
set -x TEST2_PATH color:red font:serif
exec fish
echo $TEST2 # color\:red:font\:serif
echo $TEST2_PATH #=> color:red font:serif

Jawohl. Meine Hypothese ist, dass das Exportieren von Arrays außerhalb von Pfadlisten nicht üblich ist.

MANPATH hat eine besondere Bedeutung für doppelte Doppelpunkte (::) - siehe #2090 - wirft das einen Strich durch die Rechnung?

Ich würde auch argumentieren, dass eine Sidecar-Variable FISH_ARRAY_VARIABLES=FOO\t:\nBAR\t;\nBAZ\t-\n in jedem Fall ein guter Hinweis für Instanzen wäre, in denen Fish aufgerufen wird, um die Array-Variablen wieder aufzunehmen, ohne andere Prozesse zu stören und ohne ein "we're Fische jetzt einbeziehen" Checker..

re: https://github.com/fish-shell/fish-shell/issues/436#issuecomment -392409659 @zanchey
Ich habe #2090 nicht im Detail gelesen, aber ich glaube, dass die Konvertierung zwischen den durch Doppelpunkte getrennten String- und Array-Formen völlig nahtlos ist (außer wenn Doppelpunkt ~nicht erscheint ~ in Array-Elementen erscheint).

Um einen Doppelpunkt in MANPATH , fügen Sie einfach eine leere Zeichenfolge an der Stelle ein, an der der Doppelpunkt erscheinen soll:

$ set -x MANPATH 1 2 '' 3
# Check if it's set
$ bash -c 'echo $MANPATH'
1:2::3

Um MANPATH mit einem Doppelpunkt zu beginnen, fügen Sie einfach ein leeres Zeichenfolgenelement am Anfang hinzu:

$ set -x MANPATH '' 1 2 3
# Check if it's set
$ bash -c 'echo $MANPATH'
:1:2:3

Ich habe hier nicht alles befolgt, aber als Benutzer möchte ich für "keine Konfiguration" plädieren.
Ich denke, set -S und splitenv sind Formen der Konfiguration. Einige Benutzer würden sie in fish.config ausführen und PYTHONPATH als Array behandeln. Andere würden dies nicht tun und würden PYTHONPATH als ein durch einen Doppelpunkt getrenntes Wort behandeln. Das Kopieren und Einfügen von Stapelüberlauf-Ratschlägen und das Ausführen von Skripten, die PYTHONPATH von einem Benutzer zum anderen manipulieren, würden dann nicht immer funktionieren ...

Eine feste "Wenn es mit PATH endet"-Regel ist konfigurationsfrei und klingt so perfekt, wie Sie es nur bekommen können :+1:
(Ich habe keine Meinung dazu, ob es die Abwärtsinkompatibilität wert ist)
Ja, set -x TEST2_PATH color:red font:serif würde als color red font serif -Array importiert werden, aber das ist der Deal mit dem Exportieren von Variablen. Sie können eine exportierte Variable nicht wirklich auf ein Array setzen, ohne zu verstehen, wie es funktioniert.

Jawohl. Meine Hypothese ist, dass das Exportieren von Arrays außerhalb von Pfadlisten nicht üblich ist.

@ridiculousfish das mag in aktuellen Muscheln zutreffen, aber ich stelle mir vor, dass Benutzer mit zunehmender Traktion von Fischen möglicherweise die Fähigkeit von Fischen nutzen möchten, Listen an untergeordnete Fischmuscheln zu senden. Ich kann mir vorstellen, dass es irgendwann Programme/Plugins geben wird, die den Status einer Fischsitzung verwalten (ich werde diesen Kommentar in ein paar Jahren noch einmal überprüfen, um zu sehen, ob dies wahr ist) und in der Lage sein, Listen universell automatisch zu de-/serialisieren wird diesen Code sauberer und weniger Workaround-y machen.


Ein ähnlicher, aber etwas anderer Gedanke: Die Behandlung PATH als Sonderfall ist ein anachronistischer Grenzfall, den Benutzer wahrscheinlich nur verstehen, wenn sie eine Vorgeschichte mit typischen Anwendungsfällen von Shells haben. Dies schränkt die Fähigkeit von Fisch ein, als allgemeine Skriptsprache verwendet zu werden, und schränkt einige potenzielle zukünftige Anwendungsfälle ein.

@ridiculousfish Ich denke, eine mögliche Lösung besteht darin, jeder Umgebungsvariablen / jedem Array ein eigenes Trennzeichen zuzuordnen (und Sie können '\x1e' oder ' ' oder ':' als Standard beibehalten). und der Benutzer, der die Umgebungsvariable erstellt, ist dafür verantwortlich, geeignete Trennzeichen auszuwählen, um Konflikte zu vermeiden. Der Befehl könnte wie folgt aussehen: set --separator ':' TMP 1 2 3 . Daher können Benutzer für diese bekannten Umgebungsvariablen einfach die entsprechenden bekannten Trennzeichen auswählen, die auch von anderen Programmen erkannt werden können und Fisch mit mehr Programmen (z. B. Python) kompatibler machen können.

Für diejenigen, die nur die letzten Kommentare lesen, nur eine Anmerkung, dass die set --separator -Empfehlung von @thuzhf dieselbe ist wie die set -S -Empfehlung, die wiederholt in diesem Thread erwähnt wird. Um mehr Kontext zu dieser Diskussion zu erhalten, können Sie auf dieser Seite nach set -S .

@szhu Tut mir leid, dass ich das vorherige set -S nicht bemerkt habe. Das will ich im Grunde auch. Mir ist auch aufgefallen, dass es einige Bedenken gab, die andere bezüglich dieser neuen Option hatten. Ich kann unten meine Gedanken zu diesen Bedenken äußern (da das Fish- Set -s nicht als Option verwendet hat, werde ich im Folgenden -s verwenden, um auf --separator $ zu verweisen):

  1. --no-modify ändert etwas. Ja, und Sie sollten den Namen so ändern, dass er eindeutig ist, z. B. --change-separator .
  2. Es gibt einige Ecken/knifflige Fälle. Dies liegt im Wesentlichen an der nicht wohldefinierten Syntax und kann natürlich vermieden werden, wenn wir eine strikte Definition der Syntax vorgeben. Zum Beispiel:

    1. Grundidee: Jede Variable (Liste) wird bei der Definition mit einem eigenen Trennzeichen verknüpft (Standard ist ' ' ). Dieses Trennzeichen wird verwendet, wenn diese Variable aus einer Zeichenfolge erstellt und in eine Zeichenfolge konvertiert wird (dies ist eine gängige Idee in einigen Sprachen wie der join() -Funktion von Python). Eine Variable wird beim Export oder wenn der Benutzer dies wünscht in einen String konvertiert.

    2. So erstellen Sie Umgebungsvariablen



      1. set ENV_VAR a b c . Ohne -s wählen wir ' ' als Standardtrennzeichen.


      2. set -s ':' ENV_VAR . In diesem Fall wird ENV_VAR auf eine leere Liste gesetzt.


      3. set -s ':' ENV_VAR a b:c d e:f . In diesem Fall sollten Benutzer, die diesen Code schreiben, klar verstehen, dass ':' das Trennzeichen ist und dass ENV_VAR ein Array wie ['a b', 'c d e', 'f'] ist und als 'a b:c d e:f' exportiert wird. Was ist, wenn Sie möchten, dass die exportierte ENV_VAR mit Leerzeichen beginnt und mit Leerzeichen endet? Sie sollten Escapes verwenden wie: set -s ':' ENV_VAR \ a b:c d e:f\ . Dann ist ENV_VAR [' a b', 'c d e', 'f '] und wird als ' a b:c d e:f ' exportiert.


      4. set -s ':' ENV_VAR a b:c d e:f $ENV_VAR . In diesem Fall hängt es davon ab, wie $ funktioniert. Wenn es so definiert ist, dass es den Zeichenfolgenwert von ENV_VAR anstelle der Liste extrahiert, dann ist dieser Befehl dasselbe wie das einfache Ersetzen von $ENV_VAR durch seinen Zeichenfolgenwert, der aus der darunter liegenden Liste konvertiert wird, und in diesem Fall ist es set -s ':' ENV_VAR a b:c d e:f:$ENV_VAR wahrscheinlich das, was Sie wirklich wollen (beachten Sie die : nach f ); Wenn es als Extrahieren der Variablen von ENV_VAR definiert ist (was eine Liste anstelle einer Zeichenfolge ist), sollte dies genau wie in Python zu einer Listenerweiterungsoperation werden. Wenn im letzteren Fall beispielsweise ENV_VAR ['x', 'y'] war, dann wird nach dieser Operation aus ENV_VAR ['a b', 'c d e', 'f', 'x', 'y'] . Was ist, wenn das vorherige Trennzeichen ENV_VAR nicht ':' ist? Im ersten Fall liegt es in Ihrer Verantwortung, sicherzustellen, dass Sie das Richtige tun, zB sollten Sie wahrscheinlich ein konsistentes Trennzeichen verwenden, indem Sie das ursprüngliche Trennzeichen in ':' ändern oder indem Sie das aktuelle Trennzeichen in das ursprüngliche ändern. Im letzteren Fall wird das Trennzeichen dieses Arrays vom ursprünglichen (egal was es ist) auf ':' gesetzt.



    3. So ändern Sie das Trennzeichen



      1. set --change-separator ':' ENV_VAR . Wenn ENV_VAR nicht existiert, sollte das Programm mit einem anderen Fehlercode als 0 beendet werden. Einfach und explizit genug.



    4. So zeigen Sie das Trennzeichen an



      1. set --view-separator ENV_VAR .



Außerdem denke ich wirklich, dass dieses Problem offensichtlich und dringend ist und ein großer Schmerzpunkt für Benutzer ist, und hoffe, dass dieses Problem so schnell wie möglich gelöst werden kann, da dies die Benutzererfahrung wirklich stark beeinträchtigt. Eigentlich habe ich bisher keine anderen (sogar sehr kleinen) Probleme bei der Verwendung von Fischen festgestellt, außer diesem so großen.

Ich denke wirklich, dass dieses Problem offensichtlich und dringend ist

@thuzhf : Ich würde sagen, du überschätzt das.

Ein Grund dafür war, dass Ihr Problem in #5169 mit $LD_LIBRARY_PATH war, aber das ist eigentlich keine Liste in Fisch! Sie sollten es wie in anderen Shells wie set LD_LIBRARY_PATH "$LD_LIBRARY_PATH:/some/path" setzen.

Fish wandelt genau drei geerbte/exportierte Variablen automatisch in Listen um:

$PATH, $MANPATH und $CDPATH. Und genau diese Liste wird beim Export mit einem ":" getrennt.

Andere "standardisierte" Variablen wie $LD_LIBRARY_PATH sollten in Fishscript nicht als Listen behandelt werden, sodass Sie dieses Problem nicht haben. Variablen, die nicht standardisiert sind, können Sie beliebig handhaben, da andere Programme damit sowieso nichts anfangen, also ist das Trennzeichen unkritisch.

@faho Danke für deine klare Erklärung. Das macht wirklich viel Sinn für mich. OK, ich kann sagen, dass dieses Problem für mich gelöst ist.

Ich habe mir das in #2090 beschriebene MANPATH-Problem angesehen. Das Szenario besteht darin, manpath so anzuhängen, dass es weiterhin Systempfade verwendet.

In der Bash würde man das als export MANPATH="$MANPATH:/new/path" schreiben. Wenn MANPATH gesetzt ist, wird dies daran angehängt. Wenn es nicht gesetzt ist, wird diesem ein Doppelpunkt vorangestellt, was ein mannspezifischer Hinweis darauf ist, Systemverzeichnisse zu verwenden. Diese Syntax funktioniert nicht in fish; Das Problem ist, dass MANPATH ein Array ist und daher "$MANPATH" Leerzeichen anstelle von Doppelpunkten enthält.

Ein Ansatz mit "gebundenen Variablen" würde es uns ermöglichen, zB fish_manpath als Array zu haben, das MANPATH als eine durch Doppelpunkte getrennte Zeichenfolge widerspiegelt. Dies könnte vollständig in Fischskript erstellt werden. Wir würden dies jedoch für alle pfadähnlichen Variablen tun wollen, nicht nur für MANPATH, und das wäre ein erheblicher Kompatibilitätsbruch, bei dem nicht klar ist, wie man damit umgeht. Es hat auch die gleichen Probleme, zB ist es umständlich, an die manpath -Array-Variable in zsh anzuhängen, sodass nicht klar ist, warum sie überhaupt existiert.

Mein Vorschlag hier macht die MANPATH-Situation weder besser noch schlechter; Ich denke, das, was man tun muss, ist, eine einfache Geschichte zum Anhängen an MANPATH zu haben, und zwar die folgende:

set -q MANPATH || set MANPATH ''
set -x MANPATH $MANPATH /new/path

Das Einfügen in config.fish ist nicht allzu schmerzhaft.

Mein Vorschlag hier macht die MANPATH-Situation weder besser noch schlechter; Ich denke, das, was man tun muss, ist, eine einfache Geschichte zum Anhängen an MANPATH zu haben, und zwar die folgende:

@ridiculousfish : Ich habe eigentlich darüber nachgedacht, noch einen Schritt weiter zu gehen: Teilen Sie diese speziellen Variablen auf ":" auch bei der Zuweisung und verbinden Sie sie mit ":" anstelle von Leerzeichen in Anführungszeichen.

Das bedeutet, wenn Sie set -gx MANPATH "$MANPATH:/new/path" machen, geht fish und führt die Teilung automatisch durch, was zu set -gx MANPATH "" /new/path führt.

Das bedeutet nun, dass ":" nicht in einem Pfad in $MANPATH (und $PATH und $CDPATH) erscheinen kann, aber sie können das sowieso nicht tun, weil es Nicht-Fisch-Dienstprogramme beschädigen würde!

Das würde es uns auch ermöglichen, vielleicht eines Tages die spezielle Handhabung zu entfernen, weil es eine kreuzkompatible Art der Handhabung hinzufügt - Sie müssten nur mit : zuweisen und es mit (string split : -- $MANPATH) verwenden

@faho Ich erwärme mich für die Idee - wie würde der Benutzer eine Variable so markieren, dass sie diese Sonderbehandlung erhält? Würde splitenv es tun?

Wie würde der Benutzer eine Variable markieren, die diese Sonderbehandlung erhält?

Meine Idee war eigentlich, das Markieren überhaupt nicht zuzulassen - belassen Sie es einfach als spezielles Verhalten für $PATH et al. Womit wir irgendwann in der Zukunft von der Auflistung wegkommen würden.

Inzwischen habe ich jedoch verstanden, dass es uns auch set EDITOR "emacs -nw" anderen Variablen hilft, dies für andere Variablen zuzulassen - z Tools, aber Fish würde es besser finden, wenn es eine Liste wäre.

Daher würde ich wahrscheinlich standardmäßig _Leerzeichen_ als Trennzeichen verwenden, es sei denn, es ist ein PATH-ähnliches (und davon auszugehen, dass dies der Fall ist, wenn der Name mit PATH endet, ist wahrscheinlich in Ordnung).

Würde splitenv das tun?

Ich mag es nicht wirklich, dafür ein weiteres Built-in einzuführen, also würde ich wahrscheinlich die Argument-to-Set-Option wählen.

Ich stimme zu, dass "Sonderfälle PATH/MANPATH/CDPATH seltsam sind; wir brauchen eine allgemeinere Lösung".

Ich schlage vor, dass wir die Sonderfälle PATH/MANPATH/CDPATH STOPPEN. Sie würden (vom Fisch-Endverbraucher) so behandelt, wie sie in anderen Schalen behandelt werden. $PATH (und die anderen) wären eine einzelne Zeichenfolge (oder im Fischjargon eine Liste mit einer Länge von 1) mit Doppelpunkten darin. Beachten Sie, dass ich mich auf die Fischbenutzererfahrung beziehe, nicht darauf, wie diese Dinge intern gehandhabt werden; Ich weiß nicht, wie die Implementierung in Fish aussehen würde - ich verlasse mich darauf, dass andere auf Probleme hinweisen.

Zugegeben, es hätte den Nachteil einer Abwärtsinkompatibilität, aber ich denke, es würde sich als großer Gewinn an Einfachheit und Eleganz lohnen. Ich denke, es würde auch # 2090 ansprechen.

Was denken alle?

5245 wurde zusammengeführt, also scheint dies gelöst zu sein.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen