Relleno de espacios en blanco al final de una cadena con otro carácter


12

Me gustaría generar hello worldmás de 20 caracteres.

printf "%-20s :\n\n" 'hello world!!'

# Actual output
hello world!!        :

# Wanted output
hello world!!========:

Sin embargo, no quiero completar con espacios sino con " = " en su lugar. ¿Cómo puedo hacer eso?

Respuestas:


9

Respuesta actualizada para ser una solución más general. vea también mi otra respuesta a continuación usando solo expansión de llave de concha y pritnf.

$ str='Hello World!'
$ sed -r ':loop; s/ (=*):$/\1=:/; t loop' <<< "$(printf '%-20s:\n' "$str" )"
Hello World!========:

¿Cómo funciona?

esto (=*):$/captura un espacio, uno o más =que seguido de dos puntos :al final de su entrada; hacemos que el conjunto =sea ​​una coincidencia grupal y \1será su referencia de referencia.

Con :loopdefinimos una etiqueta llamada loopy con t loopella saltaremos a esa etiqueta cuando a s/ (=*):$/\1=:/haya realizado una sustitución exitosa;

En la parte de reemplazo con \1=:, siempre incrementará el número de =sy retrocederá los dos puntos hasta el final de la cadena.


1
¿Entonces tiene que ajustar la bandera según cuántas palabras tenga la entrada?
— usuario1686

@grawity He actualizado mi respuesta a la solución general ahora.
— αғsнιη

20
filler='===================='
string='foo'

printf '%s\n' "$string${filler:${#string}}"

Da

foo=================

${#string}es la longitud del valor $stringy ${filler:${#string}}es la subcadena de $fillerdesde el desplazamiento ${#string}hacia adelante.

El ancho total de la salida será el ancho máximo de $fillero $string.

La cadena de relleno se jotpuede crear dinámicamente en sistemas que sí

filler=$( jot -s '' -c 16 '=' '=' )

(para 16 =en una línea). Los sistemas GNU pueden usar seq:

filler=$( seq -s '=' 1 16 | tr -dc '=' )

Otros sistemas pueden usar Perl o alguna otra forma más rápida de crear la cadena dinámicamente.


¿Por qué no usar printfpara generar el filtro que está casi disponible en todos los sistemas y la expansión de la llave con los cascos bash/szh?
— αғsнιη

@sddgob ¿Cómo lo harías con printf+ expansión de llaves bash?
— Kusalananda


17
printf "%.20s:\n\n" "$str========================="

donde %.20sestá el formato de truncamiento de cadena


2
Esta es mi humilde opinión, una mejor solución que la mía. Solo necesita una breve explicación de la cadena de formato.
— Kusalananda

12

Una forma de hacerlo:

printf "====================:\r%s\n\n" 'hello world!!'

66
¡Decir ah! Ese es un truco inteligente! Sin embargo, en realidad se imprimirá ====================\rhello world, lo que podría ser un problema si el OP necesita almacenar esto y no solo imprimirlo en la pantalla.
— terdon

también echo -e '=================\rHello World!!', pero tiene el mismo problema que @terdon señaló que.
— αғsнιη

1
@ αғsнιη Solo si es echocompatible -e. printfCasi siempre es mejor que echo, por muchas razones.
— Satō Katsura

5

Un enfoque de Perl:

$ perl -le '$k="hello world!!"; while(length($k)<20){$k.="=";} print "$k\n"'
hello world!!=======

O, mejor, @SatoKatsura señaló en los comentarios:

perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'

Si necesita admitir caracteres UTF de varios bytes, use:

PERL_UNICODE='AS' perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'

La misma idea en el shell:

v='hello world!!'; while [ ${#v} -lt 20 ]; do v="$v""="; done; printf '%s\n\n' "$v"

No es necesario un bucle: perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'. Sin embargo, esta (y todas las otras soluciones publicadas hasta el momento) se rompe si hay caracteres de varios bytes involucrados.
— Satō Katsura

@ SatōKatsura ooh, sí, eso es genial! Debería haber pensado en eso, gracias. Y sí, estaba pensando en agregar un descargo de responsabilidad por posible falla en los caracteres de múltiples bytes UTF, pero pensé que sería una complicación innecesaria en este contexto.
— terdon

Creo que perl6podría tener una manera de hacerlo correctamente incluso con caracteres de varios bytes. Pero por otro lado perl6es molesto de muchas maneras.
— Satō Katsura

@ SatōKatsura bien, para este tipo de cosa simple, debería ser suficiente simplemente configurar PERL_UNICODE='AS'. Por ejemplo: printf '%s' nóóös | perl -nle 'print length($_)'imprime 8 ("incorrecto") mientras printf '%s' nóóös | PERL_UNICODE='AS' perl -nle 'print length($_)'imprime 5 ("correcto").
— terdon

5

Otra forma es usar solo el printfcomando y generar el patrón de relleno de caracteres primero Shell Brace Expansion(puede poner el final con un área de formato de número ≥ en la que desea imprimir {1..end}) y obtener solo cada primer carácter %.1sque sea =sy luego imprimir solo los primeros 20 caracteres de longitud área de eso %.20s. Esta es una forma mejor de repetir caracteres / palabras en lugar de duplicarlos.

printf '%.20s:\n' "$str$(printf '%.1s' ={1..20})"
Hello World!!=======:

Explicaciones:

Normalmente, como Brace Expansion , Shell se expande de la {1..20}siguiente manera si imprimimos esos.

printf '%s ' {1..20}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 

Entonces, al agregarle un signo igual ={1..20}, Shell se expandirá de la siguiente manera.

printf '%s ' ={1..20}
=1 =2 =3 =4 =5 =6 =7 =8 =9 =10 =11 =12 =13 =14 =15 =16 =17 =18 =19 =20 

Y con lo printf '%.1s'que realmente significa printf '%WIDE.LENGTH', estamos imprimiendo solo una LONGITUD de las anteriores con 1 ANCHO predeterminado . así resultará =s solamente y se repetirá 20 veces.

Ahora con printf '%.20s:\n'estamos imprimiendo solo la longitud de 20 $stry si la longitud de $str<20, el resto tomará de =s generados para rellenar en lugar de espacios.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.