Si ejecuto el siguiente script simple:
#!/bin/bash
printf "%-20s %s\n" "Früchte und Gemüse" "foo"
printf "%-20s %s\n" "Milchprodukte" "bar"
printf "%-20s %s\n" "12345678901234567890" "baz"
Imprime:
Früchte und Gemüse foo
Milchprodukte bar
12345678901234567890 baz
es decir, el texto con diéresis (como ü
) es "reducido" por un carácter por diéresis.
Ciertamente, tengo una configuración incorrecta en alguna parte, pero no soy capaz de averiguar cuál podría ser.
Esto ocurre si la codificación del archivo es UTF-8.
Si cambio su codificación a latin-1, la alineación es correcta, pero las diéresis son incorrectas:
Fr�chte und Gem�se foo
Milchprodukte bar
12345678901234567890 baz
echo Früchte und Gemüse | wc -c -m
por la diferencia.printf
es.Respuestas:
POSIX requiere
printf
Es%-20s
para contar los 20 en términos de bytes no personajes a pesar de que tiene poco sentido comoprintf
es imprimir texto , formateado (véase la discusión en el Grupo Austin (POSIX) ybash
listas de correo).La
printf
construcción debash
y la mayoría de los otros proyectiles POSIX honran eso.zsh
ignora ese requisito tonto (incluso en lash
emulación), por lo queprintf
funciona como es de esperar allí. Lo mismo para laprintf
construcción defish
(no un shell POSIX).El
ü
carácter (U + 00FC), cuando se codifica en UTF-8, está formado por dos bytes (0xc3 y 0xbc), lo que explica la discrepancia.Esa cadena está hecha de 18 caracteres, tiene 18 columnas de ancho (
-L
siendo unawc
extensión GNU para informar el ancho de visualización de la línea más ancha en la entrada) pero está codificada en 20 bytes.En
zsh
ofish
, el texto se alinearía correctamente.Ahora, también hay caracteres que tienen ancho 0 (como combinar caracteres como U + 0308, la diéresis combinada) o tienen doble ancho como en muchos scripts asiáticos (sin mencionar caracteres de control como Tab) e incluso
zsh
no se alinearían esos correctamente.Ejemplo, en
zsh
:En
bash
:ksh93
tiene una%Ls
especificación de formato para contar el ancho en términos de ancho de pantalla .Eso todavía no funciona si el texto contiene caracteres de control como TAB (¿cómo podría?
printf
Tendría que saber qué tan separados están los tabuladores en el dispositivo de salida y en qué posición comienza a imprimir). Funciona por accidente con caracteres de retroceso (como en laroff
salida dondeX
(negritaX
) se escribe comoX\bX
) aunqueksh93
considera que todos los caracteres de control tienen un ancho de-1
.Como otras opciones, puedes probar:
Eso funciona con algunas
expand
implementaciones (aunque no con GNU).En los sistemas GNU, puede usar GNU
awk
cuyosprintf
recuentos en caracteres (no bytes, no anchos de visualización, por lo que aún no está bien para los caracteres de 0 o 2 anchos, pero está bien para su muestra):Si la salida va a un terminal, también puede usar secuencias de escape de posicionamiento del cursor. Me gusta:
fuente
ü
caracter se puede componer comou
+¨
, que es de 3 bytes. En el caso de la pregunta, se codifica como 2 caracteres, pero no todosü
se crean por igual.u\u308
son dos caracteres (en Unix /wc -m
sentido al menos) para un glifo / gráfico / grupo de gráficos y ya se menciona e incluye en esta respuesta.printf(3)
(poco sentido después de ese requisito de C99 que estás mencionando, gracias por eso), pero no laprintf(1)
utilidad ya que cada operador de shell u otra utilidad de texto trata con caracteres (o se modificaron para tratar también con caracteres comowc
cuál obtuvo un-m
(mientras-c
permaneció en byte ) ocut
que obtuvo un-b
después-c
podría significar algo más que bytes).En realidad, no, pero su terminal no habla latín-1 y, por lo tanto, obtiene basura en lugar de diéresis.
Puedes arreglar esto usando iconv:
(o simplemente ejecute todo el script de shell canalizado en iconv)
fuente