Comando read: Entrada Interativa em Shell Scripts

Comando read: Entrada Interativa em Shell Scripts

"Quero que meu script pause e deixe o usuario digitar um nome ou senha." Quando voce chega nesse momento, o comando read e a resposta. Neste artigo, Lina e Linny-senpai explicam passo a passo como capturar entrada do teclado e ler arquivos com read.

O Que Voce Vai Aprender

  • O que o comando read faz e por que ele e importante
  • Como usar prompts (-p), entrada oculta (-s) e timeout (-t)
  • O classico padrao while read para processar um arquivo linha por linha
  • Duas armadilhas para iniciantes: a "armadilha do pipe" e por que adicionar -r

1. O Que E o Comando read?

Conclusao: read e um builtin que le uma linha da entrada padrao e armazena em uma variavel, tornando seu script interativo.

Lina: Linny-senpai, eu estava escrevendo um shell script e cheguei num ponto onde quero que o usuario digite algo. Como faco isso?
Veterano Linny: E exatamente para isso que o comando read serve. read pega uma linha digitada no teclado e armazena em uma variavel.

O que o read faz

read e um builtin do shell que le uma linha da entrada padrao (como o teclado) e armazena em uma variavel. Use sempre que quiser que o usuario insira algo e depois usar esse valor dentro do seu script.

Lina: Um "builtin" e diferente de comandos como ls ou cat?
Veterano Linny: Boa pergunta. ls e cat sao comandos que existem como arquivos executaveis, como /bin/ls. Mas read e um recurso integrado ao proprio shell. Por isso which read geralmente nao encontra nada. Tente type read e voce vera read is a shell builtin.

2. O Uso Mais Basico

Conclusao: Digite read variavel e o shell aguarda; a linha que voce digitar antes de pressionar Enter vai para essa variavel.

Lina: Quero experimentar agora mesmo. Me mostra a forma mais simples.
Veterano Linny: Digite isso. Depois de pressionar Enter, o cursor para e espera sua entrada.
read name
Lina: Parou. Entao se eu digitar Lina aqui e pressionar Enter...?
Veterano Linny: O texto "Lina" vai para a variavel name. Vamos verificar o que esta dentro.
read name
Lina
echo "Hello, $name"
Hello, Lina

Adicione $ para ler o valor de uma variavel

O valor que voce armazenou com read name e recuperado adicionando um $ na frente, como em $name. Envolver em aspas duplas como echo "$name" e o estilo seguro: lida corretamente com valores que contem espacos.

3. Exibindo um Prompt (-p)

Conclusao: read -p "mensagem" variavel exibe um prompt antes da entrada para que o usuario saiba o que digitar.

Lina: Mas se o cursor simplesmente parar em silencio, o usuario nao tem ideia do que digitar, certo?
Veterano Linny: Exatamente. Entao normalmente usamos a opcao -p para exibir uma mensagem de prompt junto com a entrada.
read -p "Enter your name: " name
echo "Welcome, $name"
Enter your name: Lina
Welcome, Lina
Lina: Legal. Agora ficou obvio o que digitar.
Veterano Linny: Isso. A string apos -p e impressa como esta. Terminar com um espaco como : facilita a leitura da posicao de entrada, entao eu recomendo.

4. Lendo Varios Valores de Uma Vez

Conclusao: Liste varios nomes de variaveis apos read e a entrada separada por espacos e distribuida em cada uma.

Lina: Posso pedir varias coisas de uma vez, como nome e sobrenome?
Veterano Linny: Sim. Liste os nomes das variaveis separados por espacos apos read. Se a entrada tambem for separada por espacos, cada valor vai para a variavel correspondente.
read -p "First and last name: " first last
echo "First: $first / Last: $last"
First and last name: Lina Yamada
First: Lina / Last: Yamada

Entrada extra vai para a ultima variavel

Com read a b (duas variaveis) mas entrada 1 2 3 4, a recebe 1 e b recebe todo o restante (2 3 4). Se houver pouca entrada, as variaveis restantes ficam vazias.

5. Ocultando Entrada de Senha (-s)

Conclusao: read -s nao exibe os caracteres digitados, entao use para senhas e outros valores secretos.

Lina: Quando o usuario digita uma senha, mostrar na tela e um problema, nao e?
Veterano Linny: E ai que entra a opcao -s (silent). Os caracteres digitados nao sao exibidos na tela. Use ao ler senhas ou valores secretos.
read -s -p "Password: " pass
echo
echo "Characters entered: ${#pass}"
Password:
Characters entered: 8
Lina: Nada apareceu enquanto eu digitava, mas o valor foi capturado mesmo assim.
Veterano Linny: Isso. -s apenas oculta a exibicao; o valor e armazenado com seguranca na variavel. Como -s tambem suprime a quebra de linha quando voce pressiona Enter, adicionar um echo logo depois mantem a saida organizada. ${#pass} e a sintaxe para o comprimento de uma variavel.

6. Adicionando um Limite de Tempo (-t)

Conclusao: read -t segundos faz o read desistir automaticamente se nenhuma entrada chegar dentro do tempo especificado.

Lina: Se ninguem digitar nada, o script fica travado para sempre, certo?
Veterano Linny: Para evitar isso, use -t (timeout). Ele espera o numero de segundos especificado e segue em frente se nao houver entrada.
if read -t 5 -p "Type within 5 seconds: " answer; then
    echo "You entered: $answer"
else
    echo
    echo "Time's up"
fi

Voce pode testar se o read teve sucesso com if

read retorna "sucesso" quando le uma linha, e "falha" em timeout ou fim da entrada (mais sobre isso abaixo). Capturar isso com if read ...; then permite ramificar com base em se a entrada chegou.

7. Lendo um Arquivo Linha por Linha (while read)

Conclusao: while read line; do ... done < arquivo puxa um arquivo para uma variavel uma linha por vez para processamento.

Lina: As vezes quero processar um arquivo linha por linha, nao apenas entrada do teclado.
Veterano Linny: Para isso, a combinacao while read e a mais adequada. Esse e um padrao classico de shell scripting, entao memorize a forma completa e voce usara para sempre.
while read line; do
    echo "Read line: $line"
done < list.txt
Lina: O que e a parte < list.txt?
Veterano Linny: Isso e um redirecionamento, que significa "alimentar o conteudo de list.txt no read." Cada vez que read le uma linha, armazena em line e repete o loop ate nao haver mais linhas. Quando chega ao fim do arquivo, read retorna "falha", entao o loop termina naturalmente.

Uma forma mais segura: while IFS= read -r line

Na pratica, voce vera frequentemente while IFS= read -r line; do ... done < file. A parte IFS= evita que espacos em branco iniciais e finais sejam removidos, e -r le barras invertidas (\) literalmente. A proxima secao explica por que.

8. Duas Armadilhas que Iniciantes Encontram

Conclusao: Um while read via pipe roda em um processo separado, entao suas variaveis desaparecem, e sem -r as barras invertidas somem.

Lina: Senpai, usei while read, mas um contador que incremento dentro do loop volta a 0 depois do loop... e um bug?
Veterano Linny: Esse e um classico. Nao e um bug; e causado por como os pipes funcionam. Vamos explicar.

Armadilha 1: Variaveis Dentro de um Pipe Nao Sobrevivem

count=0
cat list.txt | while read line; do
    count=$((count + 1))
done
echo "$count"   # prints 0
Lina: Por que e 0? Estou contando corretamente dentro.
Veterano Linny: Quando voce conecta com um pipe como cat ... | while ..., a parte while roda em um processo separado (um subshell). Incrementar count la so muda um "clone." O count original nunca e atualizado.

Correcao: use redirecionamento em vez de pipe

count=0
while read line; do
    count=$((count + 1))
done < list.txt
echo "$count"   # counts correctly

Com o redirecionamento < list.txt, while roda no mesmo processo, entao a mudanca em count sobrevive.

Armadilha 2: Sem -r, Barras Invertidas Desaparecem

Lina: E a outra, -r -- por que adicionamos?
Veterano Linny: Sem -r, read trata a barra invertida (\) como especial e a remove. Por exemplo, ler o caminho C:\Users da C:Users. Entao, quando quiser ler a entrada exatamente como digitada, adicionar -r e a regra.
# Without -r: the backslashes are gone
read path <<< 'C:\Users\lina'; echo "$path"
# -> C:Userslina

# With -r: read literally
read -r path <<< 'C:\Users\lina'; echo "$path"
# -> C:\Users\lina

Na duvida, adicione -r

A menos que tenha um motivo especifico para nao adicionar, usar -r no read e a escolha segura. Linters de shell script (como ShellCheck) tambem alertam sobre um read sem -r.

9. Um Exercicio Rapido para Revisar

Lina: Aprendi bastante, entao quero escrever algo eu mesma.
Veterano Linny: Otimo. Aqui vai um pequeno desafio. Escreva um script que peca um nome e cumprimente o usuario de volta.
Exercicio: escreva um script de saudacao (clique para ver a solucao)

Tarefa: Pergunte "What's your name?", depois use o nome digitado para imprimir "Hello, NAME!"

Solucao exemplo:

#!/bin/bash
read -p "What's your name? " name
echo "Hello, ${name}!"

Ele mostra um prompt com -p e imprime o valor capturado com $name. Envolver como ${name} com chaves torna o limite da variavel claro e seguro.

Lina: Pronto. Mostrar um prompt com read -p, depois exibir com $name.
Veterano Linny: Essa e a ideia. read e um comando curto, mas uma vez que voce domina -p, -s, -t e while read, consegue lidar com quase qualquer situacao de "capturar entrada". A partir daqui, basta continuar usando em scripts reais para ganhar fluencia.

Resumo

Pontos-chave do comando read

  • read variavel armazena uma linha da entrada padrao em uma variavel
  • -p "mensagem" exibe um prompt que pede a entrada
  • -s oculta a entrada da tela (bom para senhas)
  • -t segundos define um timeout na espera pela entrada
  • while read line; do ... done < arquivo processa um arquivo linha por linha
  • Use redirecionamento (< arquivo) em vez de pipe, e adicione -r, para a forma segura

Depois de dominar read, seus scripts evoluem de "coisas que simplesmente rodam sozinhas" para "coisas que interagem com o usuario." Em seguida, va para Fundamentos de Shell Scripting para aprender a combinar a entrada capturada com condicionais e loops.