|
From: | Julio C. Neves |
Subject: | Re: [shell-script] Função para desenhar caixas |
Date: | Tue, 23 Feb 2016 22:44:48 -0300 |
Já tinha mandado a 10ª edição deste livro para a editora quando o Alfredo Casanova, colega da lista shell-script do yahoo groups, mandou a seguinte dica para a nossa lista:
"Só compartilhando uma funçãozinha que fiz aqui pra desenhar caixas de mensagem (só funciona para mensagens com uma linha, se alguém quiser alterar, à vontade)"
E nos brindou com esse código:
function DrawBox
{
string="$*";
tamanho=${#string}
tput setf 3; printf "\e(0\x6c\e(B"
for i in $(seq $tamanho)
do printf "\e(0\x71\e(B"
done
printf "\e(0\x6b\e(B\n"; tput sgr0;
tput setf 3; printf "\e(0\x78\e(B"
tput setf 4; tput bold; echo -n $string; tput sgr0
tput setf 3; printf "\e(0\x78\e(B\n"; tput sgr0;
tput setf 3; printf "\e(0\x6d\e(B"
for i in $(seq $tamanho)
do printf "\e(0\x71\e(B"
done
printf "\e(0\x6a\e(B\n"; tput sgr0;
}
Seu uso seria da seguinte forma:
$ DrawBox Qualquer frase que caiba no terminal
Só que essa caixa é azul (tput setf 3) e as letras são vermelhas, com ênfase (tput setf 4; tput bold).
Mas observe a tabela a seguir, ela explica os códigos gerados por esse monte de printf estranho:
O printf |
Produz |
\e(0\x6c\e(B |
┌ |
\e(0\x71\e(B |
─ |
\e(0\x6b\e(B |
┐ |
\e(0\x78\e(B |
│ |
\e(0\x6d\e(B |
└ |
\e(0\x6a\e(B |
┘ |
Como eu tinha acabado de escrever os exemplos que vimos acima e ainda estava com eles na cabeça, sugeri que o for que ele usou para fazer as linhas horizontais fosse trocado, assim substituiríamos:
for i in $(seq $tamanho)
do printf "\e(0\x71\e(B"
done
Por:
printf -v linha "%${tamanho}s" ' '
printf -v traco "\e(0\x71\e(B"
echo ${linha// /$traco}
Tudo Shell puro, pois o for, printf e o echo são bultins, mas como o printf dentro do for seria executado tantas vezes quantos traços horizontais houvessem, imaginei que a minha solução fosse um pouco mais veloz e pedi-lhe para testar os tempos de execução, não sem antes apostar um chope. Ele criou 2 scripts um que executava mil vezes a função que ele havia proposto e outro que fazia o mesmo com a minha solução. Não vou dizer qual foi a forma mais veloz, porém lhes adianto que o Alfredo está me devendo um chope... ;)
========================================
Ou seja, desde a 10ª edição, teu nome e tua dívida estão sacramentados no meu livro para a posteriade. ;)
Valeu Alfredo. Obrigado pelo help on line.
Upando a pedido do Julio Neves
Em sáb, 2 de ago de 2014 11:11, Alfredo Casanova <address@hidden> escreveu:Bom, rodei todas novamente (dessa vez com o carregador plugado na tomada hahah) e os resultados foram consideravelmente melhores. rodei as 3 dentro de um loop só:for n in 2 3 4; do echo $n; time for (( k=1; k<=1000; k++ )); do drawBox$n ae >/dev/null ; done; done
2real 0m12.287suser 0m7.495ssys 0m5.416s3real 0m12.253suser 0m7.460ssys 0m5.427s4real 0m12.246suser 0m7.448ssys 0m5.431s
drawBox2 é a sua versão com o printf -v traco dentro dela.drawBox3 é a modificacao que fiz dela, colocando a variável traco no ambiente antes de executar a funcao.drawBox4 é a minha versao com a alteração do for.Rodei 3 vezes e a drawBox4 foi um pouco mais rápida em todas.porém... quando mudei a frase (o loop anterior gerava caixas com 2 caracteres apenas) e coloquei uma string maior, as soluções baseadas na sua ideia conseguiram desempenho bem melhor, por volta de 0,5s em 1000 iterações.
$ for n in 2 3 4; do echo $n; time for (( k=1; k<=1000; k++ )); do drawBox$n uma frase bem maior que aeeeeeee >/dev/null ; done; done2real 0m12.344suser 0m7.640ssys 0m5.337s3real 0m12.228suser 0m7.528ssys 0m5.345s4real 0m13.093suser 0m8.379ssys 0m5.359sTe devo um chopp! hahaha2014-08-02 10:56 GMT-03:00 Alfredo Casanova <address@hidden>:
é hora da verdade.Minha primeira função rodou 1000 vezes:real 0m24.107suser 0m12.602ssys 0m14.021sCom as alterações que você sugeriu:real 0m16.421suser 0m8.289ssys 0m9.094sfiz uma terceira versão, colocando a variável $traco q voce criou fora da funcao, para evitar a execucao daquela linha a cada caixa criada (curiosamente demorou mais)real 0m16.764suser 0m8.491ssys 0m9.266scomo não aceito a derrota facilmente, resolvi mudar minha funcaoonde estava for i in $(seq $tamanho), mudei para for (( i=1; i<=$tamanho; i++ )), eliminando 2 forks também:real 0m16.837suser 0m8.589ssys 0m9.221scomo os resultados foram muito proximos, rodei com 1500 iterações as 3 ultimas opcoes.a sua primeira sugestão foi novamente a mais rápida.
Só não entendi como ela poder ter sido mais rápida que a outra, exatamente igual, com um printf a menos!
2014-08-02 9:48 GMT-03:00 'Julio C. Neves' address@hidden [shell-script] <address@hidden>:
Perdendo ou ganhando, não importa, o que vale é que de qq forma tomamos um chope regado a Shell. ;)
Em 2 de agosto de 2014 00:21, Alfredo Casanova address@hidden [shell-script] <address@hidden> escreveu:
Hahahaha tá valendo. Amanhã testo e informo.
Em 01/08/2014 22:08, "'Julio C. Neves' address@hidden [shell-script]" <address@hidden> escreveu:
Interessante... Eu até apostaria o chope que usando expansão de parâmetros seria ligeiramente mais rápido e perderia. Mas tudo bem, seria um bom pretexto para tomar um chope. De qq forma valeu pela dica: para traçar uma linha da largura da tela, basta fazer:$ printf -v Espacos %$(tput cols)s$ tr ' ' - <<< "$Espacos"Huuum!! Com o uso deste 'printf -v variável' vi que posso acelerar a minha proposta anterior, pq evita forks do Shell. Por favor, confira tb o tempo para fazer a caixa da seginte maneira:$ string="$*"$ tamanho=${#string}$ printf -v traco "\e(0\x71\e(B"$ printf -v linha "%${tamanho}s" ' '$ echo ${linha// /$traco}Alfredo, acho que agora ficará um pouco mais rápida que o for. Valendo o chope??? ;)Em 1 de agosto de 2014 15:10, Alfredo Casanova address@hidden [shell-script] <address@hidden> escreveu:
Júlio, mandei gerar 1000 caixas usando o printf dentro do for:real 0m31.460suser 0m1.624ssys 0m3.768se depois mil usando a expansão de variável que você sugeriu:real 0m39.577suser 0m3.424ssys 0m7.028srodei depois testes com apenas 100 duas vezes e em todas a versão com o for se saiu melhor2014-08-01 12:34 GMT-03:00 'Julio C. Neves' address@hidden [shell-script] <address@hidden>:
Eu usei o tput cols, como forma de apresentar mais novidades, como fazer um separador na tela inteira, mas no caso da sua caixa, me lembro que vc isolou o tamanho da msg que vc queria "encaixotar" na variável $tamanho. Então vc poderia ter evitado o for, fazendo assim:$ string="$*"$ tamanho=${#string}$ traco=$(printf "\e(0\x71\e(B")$ linha=$(printf "%${tamanho}s" ' ')$ echo ${linha// /$traco}Creio que isso te daria um pouco mais de velocidade de execução, mas tem de testar.
Em 1 de agosto de 2014 10:17, Alfredo Casanova address@hidden [shell-script] <address@hidden> escreveu:
esse notify-send não tá disponível no meu debian por default, tive que instalar um pacote mpdcron para usa-lo. É bem bacana, o caso da minha função era só pra mostrar em sessões de puro shell mesmo.A dica do tput cols é boa, mas eu usei o tamanho da string pra mostrar, assim a caixinha fica do tamanho da mensagem2014-08-01 8:49 GMT-03:00 address@hidden [shell-script] <address@hidden>:
Grande mestre Júlio!
Essa do "notify-send" é mais uma dica matadora.Impressionante o quanto eu descubro que o software livre pode propiciar de surpresas.E funcionou uma maravilha no Slackware, no Ubuntu, no Mint e no bom e velho Debian.[]'sItamar--
[]'s
Alfredo Casanova
Linux User #228230
msn: address@hidden
tel: +55 61 9655 9619
--
[]'s
Alfredo Casanova
Linux User #228230
msn: address@hidden
tel: +55 61 9655 9619
[Prev in Thread] | Current Thread | [Next in Thread] |