Warum wirkt die Substitution von Bash Extended-Globbing-Variablen auf Byte-Ebene?

7

Ich dachte, dass Bash-Variablensubstitution und Globbing bei der Zeichenauflösung funktionieren , daher war ich ziemlich überrascht, dass es auf Byte- Ebene funktioniert .
Alles in meinem localeist en_AU.UTF-8

Wenn nichts übereinstimmt und das Muster Null-zu-Viele zulässt, erfolgt die Ersetzung auf Byte- Ebene, wie durch nachfolgende Ersetzungen gesehen wird. Ich hätte erwartet, dass es zum nächsten Charakter übergeht , aber es tut es nicht ...

Vielleicht ist dies nur ein verrücktes Randmuster, oder ich vermisse etwas Offensichtliches, aber ich frage mich, was hier vor sich geht, und kann ich dieses Verhalten anderswo als in diesem bestimmten Muster erwarten?

Hier ist das Skript (das als Versuch begann, eine Zeichenfolge in Zeichen aufzuteilen).
Ich habe erwartet, dass der letzte Test mit Zeichen nur ein einziges Leerzeichen vor dem Zeichen hat, aber stattdessen wird den 3 UTF-8-Bytes des Zeichens jeweils ein Leerzeichen vorangestellt. Dies führt zu einer ungültigen UTF-8-Ausgabe.

shopt -s extglob
for str in  $'\t' "ab"   ;do
    printf -- '%s' "${str//*($'\x01')/ }" |xxd
done

Ausgabe:

0000000: 2009                                      .
0000000: 2061 2062                                 a b
0000000: 20e0 20a4 20b3                            . . .
Peter.O
quelle
Welche Version von Bash verwenden Sie?
BSD
Ich frage, weil das Bash-Änderungsprotokoll 67 Verweise auf 'Multibyte' enthält . Insbesondere bbbb.
BSD
Ich verwende GNU Bash 4.1.5 ... genauer: GNU Bash, Version 4.1.5 (1) -Version (i486-pc-linux-gnu) unter Ubuntu 10.04.4 LTS lucid ... Linux 2.6.32 -38-generic-pae GNU / Linux
Peter.O

Antworten:

4

Die kurze Antwort auf Ihre Frage lautet, dass * (Musterliste) mit null oder mehr Vorkommen der angegebenen Muster übereinstimmt. Zwischen jedem der Eingangsbytes befinden sich null Instanzen des Unicode-Zeichens 0001. Die Ersetzungsoperation ersetzt also jede dieser Nullinstanzen durch ein einzelnes Leerzeichen.

Vielleicht wollten Sie das tun:

$ for str in  $'\t' "ab"   ; do  
    printf -- '%s' "${str//+($'\x01')/ }" |xxd
  done)
0000000: 09                                       .
0000000: 6162                                     ab
0000000: e0a4 b3                                  ...

Die längere Antwort lautet jedoch, dass Pfadnamen auf keinen Fall Text sind. Zumindest sind sie nicht so weit wie das (Unix-ähnliche) Betriebssystem. Sie sind Byte-Sequenzen. Das Problem ist, dass solche Dinge trivial sind:

$ LC_ALL=latin1
$ mkdir 'áñ' && cd 'áñ'
$ LC_ALL=ga_IE.iso885915@euro
$ mkdir '€25' && cd '€25'
$ LC_ALL=zh_TW
$ pwd
# ... what should the output be?  And what about the output of:
$ /bin/pwd

Jedes dieser Gebietsschemas enthält Zeichen, die in den anderen nicht vorhanden sind. Dieses Problem betrifft auch Dinge wie locate -r und find -regex . Das Argument von locate -r ist ein regulärer Ausdruck, der daher die Unterstützung von Dingen wie Zeichenklassen beinhalten muss. Sie wissen jedoch nicht, mit welchem ​​Gebietsschema Sie die Zeichenklassen für die Zeichen in den Pfadnamen bestimmen sollen oder ob es ein einziges verwendbares Gebietsschema gibt, mit dem alle Pfade im System dargestellt werden können.

James Youngman
quelle
Dies bedeutet, dass ${str//@($'\xB3')/w}nur das letzte (UTF-8) Byte von (\ xB3) durch die Zeichenfolge w (\ x77) ersetzt werden kann , und das tut es auch! Auch ${str//*($'\xB3')/w}sollte dazu führen 77e0 77a4 77, und es tut! .. Danke James. Also, das würde bedeuten , dass in der Antwort, sollte es lesen Es sind keine Fälle von Unicode - Zeichen 0001 zwischen jedem der Eingangsbytes (nicht Zeichen) .
Peter.O