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 -mpor la diferencia.printfes.Respuestas:
POSIX requiere
printfEs%-20spara contar los 20 en términos de bytes no personajes a pesar de que tiene poco sentido comoprintfes imprimir texto , formateado (véase la discusión en el Grupo Austin (POSIX) ybashlistas de correo).La
printfconstrucción debashy la mayoría de los otros proyectiles POSIX honran eso.zshignora ese requisito tonto (incluso en lashemulación), por lo queprintffunciona como es de esperar allí. Lo mismo para laprintfconstrucció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 (
-Lsiendo unawcextensió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
zshofish, 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
zshno se alinearían esos correctamente.Ejemplo, en
zsh:En
bash:ksh93tiene una%Lsespecificació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?
printfTendrí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 laroffsalida dondeX(negritaX) se escribe comoX\bX) aunqueksh93considera que todos los caracteres de control tienen un ancho de-1.Como otras opciones, puedes probar:
Eso funciona con algunas
expandimplementaciones (aunque no con GNU).En los sistemas GNU, puede usar GNU
awkcuyosprintfrecuentos 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\u308son dos caracteres (en Unix /wc -msentido 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 comowccuál obtuvo un-m(mientras-cpermaneció en byte ) ocutque obtuvo un-bdespués-cpodrí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