Preenchendo espaços em branco à direita em uma string com outro caractere


12

Eu gostaria de produzir hello worldmais de 20 caracteres.

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

# Actual output
hello world!!        :

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

No entanto, não quero concluir com espaços, mas com " = ". Como faço isso?

Respostas:


9

Resposta atualizada para ser uma solução mais geral. veja também minha outra resposta abaixo usando apenas shell brace expansion e pritnf.

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

Como funciona?

isso (=*):$/captura um espaço, um ou mais =que é seguido por dois pontos :no final de sua entrada; fazemos o conjunto =como uma correspondência de grupo e \1será sua referência anterior.

Com :loopnós definimos um rótulo nomeado loope com t loopele pularemos para esse rótulo quando um s/ (=*):$/\1=:/fizer uma substituição bem-sucedida;

Em substituição a \1=:, sempre aumentará o número de se =retornará os dois pontos até o final da string.


1
então você precisa ajustar o sinalizador, dependendo de quantas palavras a entrada possui?
user1686

@ grrawity Atualizei minha resposta para a solução geral agora.
αғsнιη

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

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

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

${#string}é o comprimento do valor $stringe ${filler:${#string}}é a substring $fillerdo deslocamento em ${#string}diante.

A largura total da saída será a largura máxima de $fillerou $string.

A cadeia de preenchimento pode, em sistemas que possui jot, ser criada dinamicamente usando

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

(para 16 =em uma linha). Os sistemas GNU podem usar seq:

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

Outros sistemas podem usar Perl ou alguma outra maneira mais rápida de criar a string dinamicamente.


por que não usar printf para gerar o filtro que está quase disponível em todos os sistemas e a expansão de braçadeiras com cascas como bash/szh?
αғsнιη

@sddgob Como você faria isso com a printfexpansão + brace bash?
Kusalananda


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

onde %.20sé o formato de truncamento de string


2
Esta é IMHO, uma solução melhor que a minha. Ele precisa apenas de uma breve explicação sobre a string de formato.
Kusalananda

12

Uma maneira de fazer isso:

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

6
Ha! Esse é um truque inteligente! No entanto, ele será impresso ====================\rhello world, o que pode ser um problema se o OP precisar armazenar isso e não apenas imprimi-lo na tela.
terdon

também echo -e '=================\rHello World!!', mas tem o mesmo problema que o @terdon apontou isso.
αғsнιη

1
@ αғsнιη Apenas se houver echosuporte -e. printfquase sempre é melhor que echo, por muitas razões.
Satō Katsura

5

Uma abordagem Perl:

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

Ou melhor, @SatoKatsura apontou nos comentários:

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

Se você precisar oferecer suporte a caracteres de vários bytes UTF, use:

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

Mesma idéia no shell:

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

Você não precisa de um loop: perl -le '$k = "hello world!!"; print $k, "=" x (20-length $k), "\n"'. No entanto, essa (e todas as outras soluções postadas até o momento) são interrompidas se caracteres de vários bytes estiverem envolvidos.
Satō Katsura

@ SatōKatsura ooh, sim, isso é legal! Deveria ter pensado nisso, obrigado. E sim, eu estava pensando em adicionar um aviso de isenção por possível falha nos caracteres de vários bytes UTF, mas imaginei que seria uma complicação desnecessária nesse contexto.
terdon

Eu acho que perl6pode ter uma maneira de fazê-lo corretamente, mesmo com caracteres de vários bytes. Mas, por outro lado, perl6é irritante de muitas maneiras.
Satō Katsura

@ SatōKatsura bem, para esse tipo de coisa simples, deve ser o suficiente para definir PERL_UNICODE='AS'. Por exemplo: printf '%s' nóóös | perl -nle 'print length($_)'imprime 8 ("incorreto") enquanto printf '%s' nóóös | PERL_UNICODE='AS' perl -nle 'print length($_)'imprime 5 ("correto").
terdon

5

Outra maneira é usar apenas o printfcomando e gerar primeiro o padrão de preenchimento de caracteres Shell Brace Expansion(Você pode finalizar com um número ≥ da área de formatação em que deseja imprimir {1..end}) e obter apenas cada primeiro caractere %.1sque seja =s e depois imprimir apenas os primeiros 20 caracteres área disso %.20s. Essa é a maneira melhor de repetir caracteres / palavra em vez de duplicá-los.

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

Explicações:

Normalmente, como expansão de chaves , expansão de shell da {1..20}seguinte forma, se as imprimirmos.

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

Portanto, com a adição de um sinal de igual ={1..20}, o shell se expandirá da seguinte forma.

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

E com o printf '%.1s'que realmente significa printf '%WIDE.LENGTH', estamos imprimindo apenas um COMPRIMENTO daqueles acima com o padrão 1 WIDE . assim resultará =apenas se 20 vezes se repetiu.

Agora, com printf '%.20s:\n'estamos imprimindo apenas o comprimento de 20 $stre se o comprimento for $str<20, o restante levará de =s gerados para preencher em vez de espaços.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.