En un sistema de archivos donde los nombres de archivo están en UTF-8, tengo un archivo con un nombre defectuoso; se muestra como:, D�sinstaller
nombre real de acuerdo con zsh:, D$'\351'sinstaller
Latin1 para Désinstaller
sí mismo, una barbarie francesa para "desinstalar". Zsh no coincidiría con él, [[ $file =~ '^.*$' ]]
pero lo haría con un problema: este *
es el comportamiento que espero.
Ahora todavía espero encontrarlo cuando lo find . -name '*'
ejecuto; de hecho, nunca esperaría que un nombre de archivo falle esta prueba. Sin embargo, con LANG=en_US.utf8
, el archivo no aparece, y tengo que configurarlo LANG=C
(o en_US
, o ''
) para que funcione.
Pregunta: ¿Cuál es la implementación detrás y cómo podría haber predicho ese resultado?
Información: Arch Linux 3.14.37-1-lts, find (GNU findutils) 4.4.2
convmv
convertir nombres de archivo a utf-8?[[ $file =~ '^.*$' ]]
no usarrecode
el nombre del archivo, pero ahora lo investigaréconvmv
si es necesario. Gracias.Respuestas:
Esa es una muy buena captura. De un vistazo rápido al código fuente de GNU find, diría que esto se reduce a cómo se
fnmatch
comporta en secuencias de bytes no válidas (pred_name_common
enpred.c
):Este código prueba el valor de retorno de
fnmatch
igualdad con 0, pero no verifica los errores; esto da como resultado que cualquier error sea reportado como "no coincide".Se sugirió, hace muchos años, cambiar el comportamiento de esta función libc para que siempre devuelva verdadero en el
*
patrón, incluso en nombres de archivos rotos, pero por lo que puedo decir, la idea debe haber sido rechazada (vea el hilo que comienza en https : //sourceware.org/ml/libc-hacker/2002-11/msg00071.html ):Según lo mencionado por Stéphane Chazelas en un comentario, y también en el mismo hilo de 2002, esto es inconsistente con la expansión glob realizada por los proyectiles, que no ahogan los caracteres no válidos. Quizás aún más desconcertante es el hecho de que revertir la prueba solo coincidirá con aquellos archivos que tienen nombres rotos (cree archivos en bash con
touch $'D\351marrer' $'Touch\303\251' $'\346\227\245\346\234\254\350\252\236'
):Entonces, para responder a su pregunta, podría haber predicho esto al conocer el comportamiento de su
fnmatch
en este caso y al saber cómofind
maneja el valor de retorno de esta función; probablemente no podría haberlo descubierto únicamente leyendo la documentación.fuente
*
es que entonces sería incompatible conD*staller
.D*staller
coincidiera$'D\351sinstaller'
tan bien como en el conjunto de todos los proyectiles que he probado. Dado que el comportamiento de GNU fnmatch no es consistente con el del shell GNU, diría que es un error..
solo debe coincidir con caracteres válidos en la codificación, de ahí mi expectativa de que.*
no coincida con cadenas no válidas, pero no puedo encontrar una especificación coincidente para la estrella globbing.-name '*'
coincide con todos los archivos, incluidos los nombres rotos incluidos), por lo que presumiblemente es la versión de BSDfnmatch
, que no reclama POSIX.2 cnoformance, a diferencia de la versión de GNU, tiene una interpretación diferente y posiblemente más sensata de lo que se debe hacer con caracteres no válidos.La
-name
opción de búsqueda utiliza la notación de coincidencia de patrón de shell para realizar la coincidencia del nombre de archivo.*
es un patrón que coincide con varios caracteres , debe coincidir con una cadena de cero o más caracteres.find
usa fnmatch para verificar la coincidencia de patrones, por lo que puede usar ltrace para verificar el resultado:Con
D\351sinstaller
,fnmatch
return-1
, indicó que no pudo coincidir. Seሒaa
emparejará un carácter válido como .En su caso, con la
UTF-8
configuración regional,\351
es un carácter no válido, lo que hace que falle la coincidencia de patrones.fuente
ltrace
. Lo sabíastrace
, peroltrace
es nuevo para mí. ¡Encantador!