Mudança De Base No Linux

Introdução

Frequentemente precisamos converter números de uma base para outra, seja para uma análise rápida, seja programando. O ambiente GNU/Linux oferece algumas ferramentas para trabalharmos com conversão de bases e serão elas que veremos nesse post.

Programas usados

Usarei os seguintes programas para exemplificar algumas mudanças de bases:

  • bash
  • printf
  • bc
  • dc

Convertendo bases numéricas usando o bash

O bash, através do operador $(()), consegue converter qualquer base entre 2 e 64 para a base decimal. A sintaxe é:

$ echo $(([IBASE]#[numero]))

Converter de hexadecimal para decimal

$ echo $((16#FFFFAAAA))
4294945450

Converter de binário para decimal

$ echo $((2#1001111010))
634

Veja que a saída é sempre na base decimal e isso limita bastante o uso desse operador.

Convertendo bases numéricas usando o comando printf

O comando printf é tanto um built-in de alguns shells quanto um comando externo. Se você estiver usando o bash então esse comando é integrado a ele e portanto será executado quando o comando printf for invocado. Em outros shells, que não possuem esse comando como built-in, o comando externo será usado.

Esse comando se assemelha muito com a função printf() encontrada na linguagem C, pois ambas as implementações utilizam strings de formato. A lista de formatos usada por printf é muito grande (veja uma em [1]) e somente os formatos dedicados à conversão de bases que serão usados aqui.

O modo básico de chamar o comando printf é:

$ printf [formato] [argumentos...]

Sendo que os formatos usados para converter números são:

+----------+----------------------------------------------------+
| Formato  |                      Descricao                     |
+----------+----------------------------------------------------+
|   %x     |    converte o argumento para a base hexadecimal    |
+----------+----------------------------------------------------+
|   %o     |       converte o argumento para a base octal       |
+----------+----------------------------------------------------+
|   %d     | converte o argumento para a base decimal com sinal |
+----------+----------------------------------------------------+
|   %u     | converte o argumento para a base decimal sem sinal |
+----------+----------------------------------------------------+

 

Os argumentos podem ser especificados em outras bases seguindo o formato aceito pelo bash.

 

+----------+-------------------------------+
| Formato  |           Descricao           |
+----------+-------------------------------+
|    N     |   argumento na base decimal   |
+----------+-------------------------------+
|   0N     |    argumento na base octal    |
+----------+-------------------------------+
| 0[xX]N   | argumento na base hexadecimal |
+----------+-------------------------------+

 

Agora vamos converter alguns números usando printf:

Converter de decimal para hexadecimal

$ printf "%x\n" 123456
1e240
$ printf "%#x\n" 123456
0x1e140
$ printf "%x" -1
ffffffffffffffff

Pelo último exemplo, parece que minha versão do printf está trabalhando com números de 64 bits (meu sistema é 32). Veja também que isso é uma limitação, então tome cuidado para que o número de entrada não seja grande o suficiente para causar um overflow.

Converter de hexadecimal para decimal

$ printf "%d" 0x1e240
123456

Os exemplos são muitos, veja o link [1] para mais formatos e modificadores de printf. Veja que a conversão só ocorre entre as bases: decimal, hexadecimal e octal. O formato deve indicar a base de saída enquanto o argumento indica a base de entrada.

Convertendo bases numéricas usando o comando bc

O bc é um calculadora de mesa muito usada em scripts, principalmente para cálculos envolvendo números de ponto flutuante. Como era de se notar, o bc também pode ser usado para converter bases numéricas.

A sintaxe para o bc (usando pipes) é:

$ echo "obase=[OBASE]; ibase=[IBASE]; [numero]" | bc

Sendo que:

obase=[OBASE] : Define a base de saída.
ibase=[IBASE] : Define a base de entrada.
[numero] : O número a ser convertido na base [IBASE].

Exemplos:

Converter de decimal para hexadecimal

$ echo 'obase=16; ibase=10; 27878178171781787171114178178280' | bc
15FDF407F3B30687308F0FDECE8

Lembre-se que o bc é uma calculadora de precisão arbitrária, então o número de entrada pode ser tão grande quanto sua memória principal suportar (portanto sem overflows aqui).

Converter de hexadecimal para binário

$ echo 'obase=2; ibase=16; 1337AAABBBCCCDDD' | bc
1001100110111101010101010101110111011110011001100110111011101

Detalhe: Para bases de entrada maiores que 10, as letras devem vir em maiúsculas.

Converter de decimal para binário

$ echo 'obase=2; ibase=10; 88178184545178392278178178227827878' | bc
10000111110111000010100101000111000011110010100000011001110110001001\
0000010100011110001100110111010001111010010100110

Claramente você pode variar obase e ibase para obter conversões diferentes. Veja que o bc fornece uma flexibilidade maior em relação a printf, pois ele pode trabalhar com qualquer base e não somente com três. Para finalizar essa parte gostaria de comentar que inverter a ordem de obase e ibase pode causar problemas. Por padrão o bc lê os números na base 10, mas quando usamos o ibase, a base padrão de leitura é alterada e com isso o número fornecido em obase não estará mais na base 10 (exceto para ibase=10). Para entender isso, veja os exemplos:

$ echo 'ibase=8; obase=16; 456' | bc

Irá converter 456 na base 8 para a base 16? Certo? Negativo. Como a base de leitura foi mudada para 8, então todos os números subsequentes serão tratados nessa base. Como o 16 na base 8 é 14, o comando acima irá realizar o mesmo que:

$ echo 'obase=14; ibase=8; 456' | bc

Então a lição é: Sempre use obase antes de ibase para evitar problemas.

Covertendo bases numéricas usando o comando dc

O dc também é uma calculadora de mesa com precisão arbitrária que nem o bc. A diferença entre as duas é que o dc usa a notação polonesa reversa para realizar os cálculos. Isso quer dizer que uma simples conta no bc:

$ echo '1 + 2*8 + 9/3' | bc

vira esse monstrinho no dc:

$ echo '1 2 8 * + 9 3 / + p' | dc

Para saber mais sobre o dc veja o link [2]. O que nos interessa aqui é como usar o dc para converter bases.

A sintaxe é:

$ echo '[OBASE]o[IBASE]i[NUMERO]p' | dc

Os comandos ‘o’ e ‘i’ definem as bases de saída e entrada respectivamente. Não esqueça do comando ‘p’ no final que serve para mostrar o resultado.

Veja alguns exemplos:

Converter de decimal para hexadecimal

$ echo '16o9887187151817817871004887428991271822783p' | dc
1D0E4AFAEAC2CF9EE1A63124274513E5BF

Converter de hexadecimal para binário

$ echo '2o16i898171A817817F817817B187181788C117AAAAp' | dc
100010011000000101110001101010000001011110000001011111111000000101111\ 000000101111011000110000111000110000001011110001000110000010001011110\
10101010101010

Detalhe: Para bases de entrada maiores que 10, as letras devem vir em maiúsculas.

Números negativos no dc devem ser prefixados por ‘_’ e não pelo sinal de menos (já que ele é usado como operador de subtração). Então, para converter números negativos use o ‘_’ como sinal:

$ echo '2o_666p' | dc # converte -666 para a base 2
-1010011010 # <-- sem complemento de dois, infelizmente.

E por fim, basta lembrar também que a regra da ordem das bases no bc também vale para o dc, então sempre use ‘o’ antes de ‘i’ para evitar problemas.

Qual programa usar para conversão de bases?

Diante de tantas possibilidades sempre vem a cabeça sobre qual método utilizar. Eu pessoalmente acho que a ordem ideal deve ser essa:

1) Se for para converter qualquer base para decimal, use o operador $(()) do bash, pois ele tende a ser mais rápido que qualquer outro método.

2) Se a conversão ficar entre as bases dec/hex/oct então use printf. Se em seu sistema esse comando for built-in então ele apresentará maior velocidade em comparação ao bc/dc [3].

3) Para conversão qualquer base para qualquer base use o bc ou dc. Em alguns casos eu prefiro o dc porque ele utiliza menos caracteres para informar as bases (‘i’ para base de entrada enquanto “ibase” no bc). Por outro lado, levando em conta que o bc é a calculadora mais popular do linux, prefiro utilizá-lo em scripts públicos porque as pessoas estão mais acostumadas com sua sintaxe.

Conclusão

Conversão de bases numéricas é muito frequente quando estamos programando em shell script. A finalidade desse texto foi apresentar algumas formas de fazer tal tarefa usando programas simples e comuns em todas distribuições GNU/Linux.

Referências

[1] The printf command (Acessado em: Setembro/2011)
http://wiki.bash-hackers.org/commands/builtin/printf

[2] dc (computer program) (Acessado em: Setembro/2011)
http://en.wikipedia.org/wiki/Dc_%28computer_program%29

[3] Bash numerical base conversion (Acessado em: Setembro/2011)
http://www.issociate.de/board/post/353146/Bash_numerical_base_conversion.html

[4] Linux / UNIX: Convert Hexadecimal to Decimal Number (Acessado em: Setembro/2011)
http://www.cyberciti.biz/faq/linux-unix-convert-hex-to-decimal-number/

2 pensamentos sobre “Mudança De Base No Linux

  1. Pingback: Bit Hacking – Manipulação de Bits | Daemonio Labs

  2. Pingback: Conversão de base numérica | Daemonio Labs

Deixe um comentário