Klammerausdruck (ohne Bereiche), der dem unerwarteten Zeichen in der Bash entspricht

20

Ich benutze Bash unter Linux. Die folgende if-Anweisung ist erfolgreich, aber sollte sie nicht einen Fehlercode zurückgeben?

if [[  = [⅕⅖⅗] ]] ; then echo yes ; fi

Das Quadrat entspricht NICHT einem der Zeichen, daher verstehe ich nicht, warum ich einen Erfolgscode erhalte.

Es ist mir wichtig, die doppelten Klammern in meinem Fall zu behalten.

Gibt es in diesem Szenario eine andere Möglichkeit, einen Bereich festzulegen, oder welche anderen Vorschläge?

TuxForLife
quelle
2
Vermutlich eine Folge all dieser Zeichen, die in Ihrem Gebietsschema eine undefinierte Sortierreihenfolge haben (und damit dieselbe sortieren). Sehen Sie sich die laufende Diskussion in der Austin-Gruppe an . Ändern Sie das Gebietsschema in C, um es zu beheben .
Stéphane Chazelas
1
Das geht hier leider Cnicht, da es sich nicht um Einzelbyte-Zeichen handelt. C.UTF-8würde tun, wo verfügbar.
Stéphane Chazelas
11
Herzlichen Glückwunsch, Sie haben es geschafft, Stéphane mit einem Thema der Austin Group zu Ihrer ersten Frage zu rufen. Das muss mindestens ⅗ eines Internets wert sein. Oder ⅘ oder sogar ■ Internet, da anscheinend die gleichen sind. Willkommen bei Unix & Linux und bitte bringen Sie weiterhin interessante Fragen mit.
Derobert

Antworten:

29

Dies ist eine Folge davon, dass diese Zeichen die gleiche Sortierreihenfolge haben.

Das werden Sie auch bemerken

sort -u << EOF




EOF

gibt nur eine Zeile zurück.

Oder das:

expr  = 

Gibt true zurück (wie von POSIX verlangt).

Die meisten mit GNU-Systemen gelieferten Gebietsschemas haben eine Anzahl von Zeichen (und sogar Folgen von Zeichen (Sortierfolgen)), die dieselbe Sortierreihenfolge haben. Bei diesen ist die Reihenfolge nicht definiert, und Zeichen, deren Reihenfolge nicht definiert ist, haben in GNU-Systemen dieselbe Sortierreihenfolge. Es gibt Zeichen, die explizit so definiert sind, dass sie die gleiche Sortierreihenfolge wie Ș und Ş haben (obwohl es (für mich jedenfalls) keine wirkliche Logik oder Konsistenz darüber gibt, wie es gemacht wird).

Das ist die Quelle ziemlich überraschender und falscher Verhaltensweisen. Ich habe das Problem vor kurzem in der Mailingliste der Austin-Gruppe (der Stelle hinter POSIX und der Single UNIX Specification) angesprochen, und die Diskussion ist ab dem 03.04.2015 noch nicht abgeschlossen.

In diesem Fall ist mir unklar , ob wo und nach welcher Sortierung [y]übereinstimmen soll. Da jedoch ein Klammerausdruck mit einem Sortierelement übereinstimmen soll, lässt dies darauf schließen, dass das Verhalten erwartet wird.xxybash

In jedem Fall denke ich, [⅕-⅕]oder [⅕-⅖]sollte zumindest übereinstimmen .

Sie werden feststellen, dass sich verschiedene Tools unterschiedlich verhalten. ksh93 verhält sich wie bashGNU grepoder sednicht. Einige andere Muscheln haben ein anderes Verhalten, andere mögen yashnoch buggyiger sein.

Für ein konsistentes Verhalten benötigen Sie ein Gebietsschema, in dem alle Zeichen unterschiedlich sortiert sind. Das Gebietsschema C ist das typische. Bei den meisten Systemen ist der Zeichensatz in der Ländereinstellung C jedoch ASCII. Auf GNU-Systemen haben Sie im Allgemeinen Zugriff auf ein C.UTF-8Gebietsschema, mit dem Sie stattdessen UTF-8-Zeichen bearbeiten können.

So:

(export LC_ALL=C.UTF-8; [[  = [⅕⅖⅗] ]])

oder das Standardäquivalent:

(export LC_ALL=C.UTF-8
 case  in ([⅕⅖⅗]) true;; (*) false; esac)

sollte false zurückgeben.

Eine andere Alternative wäre, nur LC_COLLATEauf C zu setzen , was auf GNU-Systemen funktionieren würde, aber nicht unbedingt auf anderen, bei denen es fehlschlagen könnte, die Sortierreihenfolge von Mehrbyte-Zeichen anzugeben.


Eine Lehre daraus ist, dass Gleichheit keine so klare Vorstellung ist, wie man es beim Vergleichen von Strings erwarten würde. Gleichheit könnte bedeuten, von streng bis am wenigsten streng.

  1. Die gleiche Anzahl von Bytes und alle Byte-Bestandteile haben den gleichen Wert.
  2. Die gleiche Anzahl von Zeichen und alle Zeichen sind gleich (beziehen Sie sich beispielsweise auf denselben Codepunkt im aktuellen Zeichensatz).
  3. Die beiden Zeichenfolgen haben dieselbe Sortierreihenfolge wie der Sortieralgorithmus des Gebietsschemas (d. H., Weder a <b noch b> a ist wahr).

Für 2 oder 3 wird davon ausgegangen, dass beide Zeichenfolgen gültige Zeichen enthalten. In UTF-8 und einigen anderen Codierungen bilden einige Bytefolgen keine gültigen Zeichen.

1 und 2 sind deshalb nicht unbedingt gleichwertig, oder weil einige Zeichen möglicherweise mehr als eine mögliche Kodierung haben. Dies ist in der Regel der Fall bei statusbehafteten Codierungen wie ISO-2022-JP, bei denen Aentweder 41oder ausgedrückt werden kann 1b 28 42 41( 1b 28 42die Reihenfolge, in der auf ASCII umgeschaltet wird, und Sie können so viele davon einfügen, wie Sie möchten, was keinen Unterschied macht), obwohl ich Ich würde nicht erwarten, dass diese Codierungstypen immer noch verwendet werden, und GNU-Tools funktionieren zumindest im Allgemeinen nicht richtig mit ihnen.

Beachten Sie auch, dass die meisten Nicht-GNU-Dienstprogramme den 0-Byte-Wert (das NUL-Zeichen in ASCII) nicht verarbeiten können.

Welche dieser Definitionen verwendet wird, hängt vom Dienstprogramm und der Implementierung oder Version des Dienstprogramms ab. POSIX ist diesbezüglich nicht 100% klar. In der Ländereinstellung C sind alle 3 gleichwertig. Außerhalb dieser YMMV.

Stéphane Chazelas
quelle
Ein weiterer häufiger Fall, in dem sich 1 und 2 unterscheiden, ist Unicode, beispielsweise durch das Kombinieren von Zeichen.
Gilles 'SO- hör auf, böse zu sein'
@Gilles, Zeichen kombinieren, sind Zeichen für sich. Die Kombination bildet ein Graphem / eine Zelle, besteht aber immer noch aus mehreren Zeichen. é (U + 00E9) und é (e, gefolgt von U + 0301) sind das gleiche Diagramm, aber zwei unterschiedliche Zeichenfolgen (zumindest aus Sicht der POSIX-APIs). Mit 1 und 2 wären sie unterschiedlich. Mit 3 könnten sie als gleich angesehen werden, wenn U + 0301 alle Sortiergewichte auf "IGNORE" gesetzt hätte, aber das ist im Allgemeinen nicht der Fall, da man im Allgemeinen über die Reihenfolge der Diakritika entscheiden möchte.
Stéphane Chazelas
Es ist normalerweise wünschenswert, die gleiche Zeichenfolge zu betrachten éund zu sein, aber nicht e. POSIXs Begriff der Sortierreihenfolge ist selten richtig, basiert zu stark auf Zeichen und berücksichtigt nicht die gebräuchlichsten Arten der Sortierung von Zeichenfolgen (z. B. verwenden französische Wörterbücher keine lexikografische Reihenfolge zum Sortieren von Wörtern: Sie führen eine erste lexikografische Übergabe mit ignorierten und hervorgehobenen Akzenten durch Verwenden Sie dann Akzente, um die Krawatten zu entscheiden.
Gilles 'SO- hör auf böse zu sein'
@ Gilles, ja. Deshalb würde ich sagen, dass diese Zeichen, die in glibc-Ländereinstellungen die gleiche Sortierreihenfolge (absichtlich) haben, wenig Sinn machen. Das é vs é wird in der Regel dadurch gelöst, dass zuerst einige Transformationen an den Zeichenfolgen vorgenommen werden, wie z. B. eine kanonische Zerlegung (ähnlich wie zuerst in Kleinbuchstaben konvertiert wird, wenn zwischen Groß- und Kleinschreibung unterschieden werden soll). Siehe auch den ICU-Leitfaden für eine gute Referenz zu diesem Thema.
Stéphane Chazelas
@Gilles, die Gewichte im POSIX-Algorithmus für die Sortierung von Gebietsschemas können diese Sortierung des französischen Wörterbuchs durchführen. So funktionieren die Gewichte. Ein erster Durchgang verwendet die Primärgewichte (wobei e und é (und E und É) gleich sind und der kombinierende Akzent ignoriert wird), ein zweiter Durchgang (falls gleich) prüft die Akzente, ein dritter Durchgang die Großschreibung ...
Stéphane Chazelas
-3

Du machst es falsch =und ==bist nicht dasselbe.

Probieren Sie diese Beispiele aus:

if [[ "■" == "[⅕⅖⅗]" ]] ; then echo yes ; else echo no ; fi

if [[ "1" == "1" ]] ; then echo yes ; else echo no ; fi

if [[ "■" == "■" ]] ; then echo yes ; else echo no ; fi
Amsel
quelle
1
Das ist nicht wahr. POSIX gibt an, dass der Operator =zur Überprüfung der Gleichheit verwendet werden soll. Das Problem sind die fehlenden Anführungszeichen, nicht der Operator.
3.
1
Auch man bashsagt im [[Abschnitt: „Der Operator = entspricht ==.“
Michas
1
@scai, POSIX gibt den [[...]]Operator nicht an. Und = und == sind in den Shells, in denen sie implementiert wurden (ksh / bash / zsh) und für den Mustervergleich nicht gleich.
Stéphane Chazelas
Beim Vergleich mit einem Muster darf das Muster nicht in Anführungszeichen gesetzt werden, da es sonst als wörtliche Zeichenfolge verwendet wird, daher das "Nein" im ersten Test.
Xhienne