Arquivos Mensais: junho 2007

Bash customizado, parte 2

Artigo anterior 

Aqui está a lista de cores que podem ser utilizadas. Basta copiar o código delas antes do que será escrito, e não se esqueça de no fim ‘limpar’ a cor com:

\[33[0m\] – Volta cor ao normal do terminal

Cores normais
\[33[0;30m\] – Preto
\[33[0;31m\] – Vermelho
\[33[0;32m\] – Verde
\[33[0;33m\] – Amarelo
\[33[0;34m\] – Azul
\[33[0;35m\] – Magenta
\[33[0;36m\] – Ciano
\[33[0;37m\] – Branco

Cores com negrito
\[33[1;30m\] – Preto
\[33[1;31m\] – Vermelho
\[33[1;32m\] – Verde
\[33[1;33m\] – Amarelo
\[33[1;34m\] – Azul
\[33[1;35m\] – Magenta
\[33[1;36m\] – Ciano
\[33[1;37m\] – Branco

Cores de fundo
\[33[40m\] – Preto
\[33[41m\] – Vermelho
\[33[42m\] – Verde
\[33[43m\] – Amarelo
\[33[44m\] – Azul
\[33[45m\] – Magenta
\[33[46m\] – Ciano
\[33[47m\] – Branco

Para quem tiver curiosidade, foi assim que ficaram minha PS1 e PS2 respectivamente:
\n[\W] \[33[1;34m\]\h \[33[1;32m\]\$ \[33[0m\]
[\W] \[33[1;34m\]\h \[33[1;32m\]> \[33[0m\]

Publicidade

Bash customizado, parte 1

Alterar o arquivo ~/.bashrc para que o comando ls imprima colorido (azul para diretórios, verde para executáveis, etc) não deve ser novidade para muitas pessoas que já mexam com nixes da vida já por algum tempo.

O que eu vou falar aqui é sobre algo um pouco menos conhecido, a variável PS1, como editá-la e como acrescentar cores a ela. Depois de seguido o mini-HowTo, você terá algo parecido com isso, mas mais ao seu gosto:
Screenshot do Bash

Antes de mais nada, modifique as cores do terminal que você estiver usando para algo mais agradável. As cores padrão normalmente nos remetem ao console virtual (modo texto), e embora contrastem bem tanto com o fundo branco como o fundo preto, elas não são cores muito agradáveis.

Depois de alteradas as cores, vamos alterar a variável PS1, e a PS2, se você quiser. A variável PS1 é uma string com alguns caracteres ‘chave’ que possuem valor especial, mais ou menos como uma string de controle da função printf(). É ela que controla o ‘$’ ou ‘#’ e tudo o que aparece antes deles.

Por padrão no ArchLinux, ela tem essa aparência e esse valor:
[user@host dir] $
PS1='[\u@\h \W] \$’

Experimente novas maneiras de usá-la digitando
PS1=’o que vc quer’
no próprio Bash. Não se preocupe, depois que você sair e entrar de novo no Bash, ela voltará ao normal. Nela você poderá incluir algumas informações como hora, nome de usuário, nome do servidor, etc. A minha ficou assim:
PS1=’\n[\W] \h \$ ‘

Aqui está uma lista com as opções possíveis:

  • \d a data em um formato “Dia da Semana Mês Dia” format (ex: “Tue May 26”)*
  • \e Caractere de escape ASCII (033)
  • \h Nome do servidor até o primiro `.’
  • \H Nome do servidor
  • \n Nova linha
  • \s O nome do shell, a parte que segue a última barra ($0)
  • \t A hora em 24 horas (HH:MM:SS)
  • \T A hora em 12 horas (HH:MM:SS)
  • \@ A hora em 12 horas am/pm
  • \u Nome do usuário
  • \v Versão do Bash (ex: 2.00)
  • \V O release do bash, versão + patchlevel (ex: 2.00.0)
  • \w Diretório atual (ex: /nome/do/diretório)
  • \W Base do nome do diretório (ex: diretório)
  • \! O número do comando no histórico
  • \# O número do comando
  • \$ Se a userID for 0 (root), #, senão, $
  • \nnn Um caractere representando o número octal nnn
  • \\ Uma barra invertida
  • \[ Inicia uma sequência de caracteres não imprimiveis
  • \] Termina a sequência

Esse é o fim da primeira parte. Na próxima veremos como mudar as cores e um script que mostra todas elas.

Você sabe que é um geek quando…

…você está lendo o rótulo de Listerine e depois de ler L-I-S, espera que a próxima letra seja um P.

Lisp e Bhaskara II

Pro pessoal que se interessou na primeira parte do artigo, eu acrescentei duas funções que permitem a entrada da equação como strings, está meio POG, mas funciona.

O próximo passo é implementar um loop que pergunte a equação e se repita.

Nota 1: Mesmo que a=1, ele deve aparecer na string.
Nota 2: Os sinais de b e c devem estar ‘grudados’ (sem espaço neles)
Nota 3: ‘ = 0’ é opcional.

Exemplo:

(solve-equation "1x² -4x +4 = 0")

O código dessa nova função é:

(defun parse-string (str)
  (let* ((equation (remove #\x (remove #\² str)))
         (end-a (position #\SPACE equation))
         (a (read-from-string (subseq equation 0 end-a)))
         (end-b (position #\SPACE (subseq equation (+ 1 end-a))))
         (b (read-from-string (subseq (subseq equation (+ 1 end-a)) 0 end-b)))
         (end-c (position #\SPACE (subseq (subseq equation (+ 1 end-a)) 
                                          (+ 1 end-b))))
         (c (read-from-string (subseq (subseq (subseq equation (+ 1 end-a))
                                              (+ 1 end-b))
                                      0 end-c))))
    (list a b c)))

(defun solve-equation (str)
  (let* ((abc (parse-string str))
         (a (first abc))
         (b (second abc))
         (c (third abc)))
    (say-results a b c)))

Piada Geek – Duas strings…

vão ao bar. Uma delas diz:

–  Eu quero rum e Cocaqweasdqwejkda.qwea..qwe, .

A outra string diz:

– Perdoe meu amigo, ele não é null-terminated.

Lisp e Bhaskara

Uma das principais vantagens de Lisp em relação às outras linguagens de programação é a ótima relação funcionalidade vs. número de linhas.

Em menos de 35 linhas eu tenho um aplicativo simples capaz de resolver bhaskara e imprimir os resultados de maneira legível.

(defun delta (a b c)
  "Calculates the delta from a quadratic equation."
  (- (* b b) (* a c 4)))

(defun find-x (a b c)
  "Calculates x' and x\" from a quadratic equation."
  (let ((delta (delta a b c)))
    (list
      (/ (+ (- b) (sqrt delta)) (* 2 a))
      (/ (- (- b) (sqrt delta)) (* 2 a)))))

(defun find-vertix (a b c)
  "Calculates the maximum (or minimum) value y can reach in a quadratic equation."
  (let ((delta (delta a b c)))
    (list
      (/ (- b) (* 2 a))
      (/ (- delta) (* 4 a)))))

(defun bhaskara (a b c)
  "Calculates a quadratic equation"
  (let ((delta (delta a b c))
	(xs (find-x a b c))
	(vertix (find-vertix a b c)))
    (list
      :delta delta
      :x1 (first xs)
      :x2 (second xs)
      :Vx (first vertix)
      :Vy (second vertix))))

(defun say-results (a b c)
  (format t "~{~a:~10t~a~%~}~%" (bhaskara a b c)))

E os resultados saem como:

[1]> (say-results 1 -7 6)
DELTA:    25
X1:       6
X2:       1
VX:       7/2
VY:       -25/4

NIL

Edit: Quem gostou do programa, dê uma olhada na segunda parte.

Notações Polonesa e Polonesa Reversa

18-03-2009: Tenho outro artigo sobre o assunto, caso você esteja procurando como implementar uma calculadora com RPN.

Estava brincando com o galculator no Linux (esse nome é ridículo, mas enfim) e vi que ele possui três modos de entrada: algébrico (mais ou menos como nas calculadoras de 4 funções normais), entrada de fórmulas (em que podemos digitar uma longa expressão de uma vez só, como nas calculadoras científicas da Casio) e notação polonesa reversa.

Essa última me chamou a atenção, me lembrou um pouco Lisp, só que ao contrário, então fui pesquisar mais sobre o assunto.

Basicamente, existem três tipos de notação matemática, com os operadores antes dos números (Lisp), com os operadores no meio dos números (a que estamos acostumados) e com os operadores depois dos números (me parece que algumas calculadoras da HP funcionam desse modo).

Não falarei da notação algébrica já que usamo-na no dia-a-dia. A notação polonesa foi inventada por Jan Łukasiewicz apresenta a vantagem de não ser necessário o uso de parenteses.

+ 2 3

Quer dizer “some 2 com 3”. A leitura dos números na ordem em que eles aparecem é importante, principalmente na divisão, pois poderia gerar confusão.

/ 10 5

Significa “divida 10 por 5” e resulta em 2, não em ½.

Expressões maiores podem parecer confusas no princípio, mas é apenas questão de treino. De uma maneira simples, começa-se a ler da esquerda para a direita e segue-se a seguinte ordem:

  1. Encontra-se o primeiro operador
  2. Verifica-se os dois símbolos que o seguem. Se forem dois números, resolve-se-los (que coisa mais estranha =P), se um dos dois símbolos ou ambos forem outros operadores, passa-se ao operador mais a direita.
  3. Para melhores resultados, repita o procedimento e use condicionador e creme para pentear da PolishNotation Shampoos Ltda.

Aqui está um exemplo:

* + 2 - 9 4 / 6 2

O primeiro operador a ser seguido de dois números é “- 9 4”, então vamos resolvê-lo. (Alternativamente, poderia ser resolvido “/ 6 2” ao mesmo tempo, mas vamos com calma nesse primeiro exemplo)

* + 2 5 / 6 2

Aqui podemos resolver “+ 2 5”:

* 7 / 6 2

E aqui, “/ 6 2”:

* 7 3
21

Note que não há ordem certa para resolver as operações, simplesmente segue-se da esquerda para a direita. Aqui está o código em Lisp apenas para comparação:

(* (+ 2 (- 9 4)) (/ 6 2))

A notação polonesa reversa é basicamente a mesma coisa, só que ao contrário (O RLY? YA RLY). A idéia é deixar os dois números que serão calculados ‘empilhados’ e depois escolhermos a operação.

Digamos que nós temos a seguinte operação:

(8 - 2)*(4 + 3)

Na notação polonesa reversa isso ficaria como:

8 2 - 4 3 + *

A leitura procede da mesma maneira que na notação polonesa normal, mas começando do outro lado. Primeiro resolvemos o operador a ter dois números antes dele e assim sucetivamente:

6 7 *
42 (eu juro que esse 42 foi sem querer)

Sua utilização em calculadoras ocorre da seguinte forma: ao invés de possuir um botão de =, a calculadora terá um botão ‘enter’, que servirá para armazenar números na pilha (pilha de números, não pilha equivalente a bateria). Após armazenados os números, escolhemos a operação e o resultado logo aparece.

A operação que calculamos anteriormente ficaria:

[8] [enter] [2] [-] [4] [enter] [3] [+] [*]

O que nos dá uma vantagem de dois digitos em relação a notação convencional.

Além da ausência de parenteses, a notação polonesa reversa apresenta uma vantagem na hora da implementação do algoritmo e permite a escrita de operações mais complexas com menos dígitos.