In einem Dateisystem mit Dateinamen in UTF-8 habe ich eine Datei mit einem falschen Namen. Es wird angezeigt als :, D�sinstaller
tatsächlicher Name nach zsh D$'\351'sinstaller
:, Latin1 für Désinstaller
, selbst eine französische Barbarei für " uninstall ". Zsh würde es nicht mit, [[ $file =~ '^.*$' ]]
aber mit einem Globbing vergleichen *
- das ist das Verhalten, das ich erwarte.
Jetzt erwarte ich immer noch, dass ich es beim Ausführen finde find . -name '*'
- tatsächlich würde ich nie erwarten, dass ein Dateiname diesen Test nicht besteht. Mit wird LANG=en_US.utf8
die Datei jedoch nicht angezeigt, und ich muss festlegen LANG=C
(oder en_US
oder ''
), dass sie funktioniert.
Frage: Welche Implementierung steckt dahinter und wie hätte ich dieses Ergebnis vorhersagen können?
Infos: Arch Linux 3.14.37-1-lts, find (GNU findutils) 4.4.2
convmv
, Dateinamen in utf-8 umzuwandeln?[[ $file =~ '^.*$' ]]
nicht zu verwendenrecode
, aber ich werde jetzt nachsehen,convmv
ob dies notwendig ist. Vielen Dank.Antworten:
Das ist ein wirklich schöner Fang. Bei einem kurzen Blick auf den Quellcode für GNU find würde ich sagen, dass dies darauf hinausläuft, wie
fnmatch
sich ungültige Bytesequenzen (pred_name_common
inpred.c
) verhalten :Dieser Code testet den Rückgabewert von
fnmatch
auf Gleichheit mit 0, prüft jedoch nicht auf Fehler. Dies führt dazu, dass Fehler als "nicht übereinstimmen" gemeldet werden.Es wurde vor vielen Jahren vorgeschlagen, das Verhalten dieser libc-Funktion so zu ändern, dass das
*
Muster auch bei beschädigten Dateinamen immer "wahr" ist , aber soweit ich das beurteilen kann, muss die Idee zurückgewiesen worden sein (siehe den Thread, der bei https beginnt) : //sourceware.org/ml/libc-hacker/2002-11/msg00071.html ):Wie von Stéphane Chazelas in einem Kommentar und im gleichen Thread von 2002 erwähnt, ist dies nicht mit der Glob-Erweiterung vereinbar, die von Shells ausgeführt wird, die ungültige Zeichen nicht verschlucken. Noch rätselhafter ist die Tatsache, dass beim Umkehren des Tests nur die Dateien gefunden werden, deren Namen nicht korrekt sind (erstellen Sie Dateien in Bash mit
touch $'D\351marrer' $'Touch\303\251' $'\346\227\245\346\234\254\350\252\236'
):Um Ihre Frage zu beantworten, hätten Sie dies vorhersagen können, indem Sie das Verhalten
fnmatch
in diesem Fall kennen und wissen, wiefind
mit dem Rückgabewert dieser Funktion umgegangen wird. Sie hätten es wahrscheinlich nicht allein durch Lesen der Dokumentation herausfinden können.quelle
*
gibt, ist, dass es dann widersprüchlich wäreD*staller
.D*staller
es$'D\351sinstaller'
genauso gut passt wie in der Glob aller Shells, die ich getestet habe. Da das Verhalten von GNU fnmatch nicht mit dem der GNU-Shell übereinstimmt, würde ich sagen, dass es ein Fehler ist..
nur gültige Zeichen in der Codierung übereinstimmen sollen - daher meine Erwartung, dass.*
ungültige Zeichenfolgen nicht übereinstimmen -, aber ich kann keine übereinstimmende Spezifikation für den Globbing Star finden.-name '*'
mit allen Dateien übereinstimmt, einschließlich defekter Namen), so dass vermutlichfnmatch
BSDs Version von , die nicht POSIX.2-Konformität beansprucht, hat im Gegensatz zur GNU-Version eine andere und wohl vernünftigere Interpretation dessen, was mit ungültigen Zeichen geschehen soll.Die
-name
Suchoption verwendet die Shell- Pattern-Matching-Notation , um den Dateinamen abzugleichen.*
ist ein Muster, das mit mehreren Zeichen übereinstimmt . Es muss mit einer Zeichenfolge von null oder mehr Zeichen übereinstimmen .find
Verwendet fnmatch , um die Musterübereinstimmung zu überprüfen, sodass Sie ltrace verwenden können , um das Ergebnis zu überprüfen:Mit
D\351sinstaller
,fnmatch
return-1
, wird angezeigt, dass die Übereinstimmung fehlgeschlagen ist. Ein gültiges Zeichen wieሒaa
wird abgeglichen.In Ihrem Fall ist das
UTF-8
Gebietsschema\351
ein ungültiges Zeichen, wodurch der Mustervergleich fehlschlägt.quelle
ltrace
. Ich wusste esstrace
, aber esltrace
ist neu für mich. Schön!