Se você segue o It’s FOSS no Facebook, pode estar ciente do Bash Challenge semanal. É um esforço conjunto de Yes I Know It e da It's FOSS para fornecer a você um exercício de script Bash para testar suas habilidades no Linux.
Estamos trazendo este Desafio Bash do Facebook para um público mais amplo na web regular. Esta é a 5ª edição desta série. Os primeiros 4 desafios podem ser encontrados em nossas páginas do Facebook. Você também pode comprar esses desafios na forma de livro:
Desafio Bash 5
Mostraremos uma captura de tela do terminal e pediremos que explique por que o resultado não é o que esperávamos. Obviamente, a parte mais divertida e criativa do desafio será descobrir como corrigir o (s) comando (s) exibido (s) na tela para obter o resultado correto.
Pronto para jogar? Então, aqui está o desafio desta semana:
Meu Bash não sabe contar [nível de dificuldade 1]
Esta semana, tenho alguns arquivos de dados contendo números inteiros, um em cada linha:
cat sample.data 102 071 210 153
E eu quero calcular a soma de todos esses números:
declare -i SUM=0 while read X ; do SUM+=$X done < sample.data echo "Sum is: $SUM"
Infelizmente, o resultado que obtenho está errado (o resultado esperado era 536):
Sum is: 522
Desafio
Seu desafio é encontrar:
- Por que esse resultado estava errado?
- Como consertar meus comandos para obter o resultado correto?
★ Ponto de unicórnio bônus se você puder encontrar uma solução usando apenas comandos internos Bash e/ou substituições de shell.
Estamos ansiosos para ler suas soluções na seção de comentários abaixo! Não se esqueça de ser criativo.
Alguns detalhes
Para criar este desafio, usei:
- GNU Bash, versão 4.4.5 (x86_64-pc-linux-gnu)
- Debian 4.8.7-1 (amd64)
- Todos os comandos são fornecidos com uma distribuição Debian padrão
- Nenhum comando foi alias
Solução
Como reproduzir
Aqui está o código bruto que usamos para produzir este desafio. Se você executá-lo em um terminal, poderá reproduzir exatamente o mesmo resultado exibido na ilustração do desafio (presumindo que você esteja usando a mesma versão de software que eu):
rm -rf ItsFOSS mkdir -p ItsFOSS cd ItsFOSS cat > sample.data << 'EOT' 102 071 210 153 EOT clear cat sample.data declare -i SUM=0 while read X ; do SUM+=$X done < sample.data echo "Sum is: $SUM"
Qual era o problema?
O problema foi causado pelo valor 071
. Como você notou, esse número começa com 0
- provavelmente para garantir que todos os dados sejam formatados em três dígitos. Nada complicado aqui, exceto que… seguindo uma convenção infeliz herdada da linguagem de programação C, prefixar um inteiro por 0
é uma maneira de especificar que o número é expresso em octal, e não em decimal.
Os números octais são expressos com dígitos de 0
a 7
. Aqui está uma tabela de conversão simples:
Octal Decimal 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 10 8 11 9 12 10 13 11 14 12 .. .. 71 57 Este último valor é que causou o erro na avaliação da soma. O Bash leu 071
e interpretou-o como um número octal que representa o valor decimal 57
. Você pode verificar isso facilmente:
echo $((071)) 57
Como consertar isso?
Posso ver duas estratégias principais para corrigir esse problema. Ou removendo os zeros à esquerda. Ou encontrar uma maneira de fazer o shell entender que todos os meus números são valores decimais.
Removendo zeros à esquerda
Aqui está uma solução simples usando o comando externo sed
para remover os zeros à esquerda:
declare -i SUM=0 while read X ; do SUM+=$X done < <(sed -E s/^0+// sample.data) echo "Sum is: $SUM"
(pergunta bônus: por que eu não usei um pipe em vez de uma substituição de processo?)
Especificando explicitamente a base
A solução anterior é (principalmente) direta - mas o Bash nos permite tornar as coisas melhores. Em vez de tentar corrigir os dados, simplesmente especificaremos explicitamente nossos números são expressos na base 10 (decimal), em vez da base 8 (octal). Você pode fazer isso usando a sintaxe base#value
.
Compare esses três exemplos:
echo $((071)) # The leading 0
specify the number as octal
57
echo $((8#071)) # We explicitly specify base 8 (octal)
57
echo $((10#071)) # We explicitly specify base 10 (decimal)
71
Para corrigir meu comando inicial e obter o resultado correto, só preciso especificar explicitamente a base 10 para todos os meus dados:
declare -i SUM=0 while read X ; do SUM+=$((10#$X)) done < sample.data echo "Sum is: $SUM"
E aqui está o resultado correto. Esperamos que você tenha gostado desse desafio. Fique ligado para mais diversão!
Biografia do autor: Sou Sylvain Leroux, engenheiro de software por paixão, professor por vocação. Tenho 15 anos de experiência no ensino de Ciência da Computação e Tecnologias da Informação em todos os níveis. Eu sou um forte defensor das tecnologias Linux e OpenSource. Fundei Yes I Know IT para compartilhar essa experiência com um público mais amplo por meio de cursos online e vídeos gratuitos. Não hesite em entrar em contato comigo no Twitter.
Via itsfoss.com. Você pode conferir o post original em inglês:
[Bash Challenge] Can You Solve This Bash Scripting Exercise?Última atualização deste artigo: 23 de july de 2017