[Desafio Bash] Você consegue resolver este exercício de script do Bash?

23 de julho de 2017

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]

! [Desafio Bash 5: exercício de script Bash](bash-challenege-5.webp) Desafio Bash 5: exercício de script Bash

Esta semana, tenho alguns arquivos de dados contendo números inteiros, um em cada linha:

Comandos para usar no terminal

cat sample.data 102 071 210 153

E eu quero calcular a soma de todos esses números:

Comandos para usar no terminal

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):

Comandos para usar no terminal

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):

Comandos para usar no terminal

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:

Comandos para usar no terminal

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:

Comandos para usar no terminal

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:

Comandos para usar no terminal

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:

Comandos para usar no terminal

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.

Confira também a versão original desse post em inglês
Esse post foi originalmente escrito por Abhishek Prakash e publicado no site itsfoss.com. Tradução sujeita a revisão.

[Bash Challenge] Can You Solve This Bash Scripting Exercise?

Propaganda
Blog Comments powered by Disqus.
Propaganda