Como fazer um loop, também conhecido como projetar um programa para fazer trabalho repetitivo para você
O loop é uma das construções mais fundamentais e poderosas em computação, porque nos permite repetir um conjunto de comandos, quantas vezes quisermos, sobre uma lista de itens de nossa escolha. Muito do pensamento computacional envolve pegar uma tarefa e resolvê-la de uma forma que pode ser aplicada repetidamente a todas as outras tarefas semelhantes, e o loop for é como fazemos com que o computador faça esse trabalho repetitivo:
Ao contrário da maioria do código que escrevemos até agora no prompt interativo, um loop for não é executado assim que pressionamos Enter:
Podemos escrever quantos comandos quisermos no bloco entre as palavras-chave do
e done
:
Somente até chegarmos a done
e pressionar Enter, o loop for faz seu trabalho.
Isso é fundamentalmente diferente do comando e resposta linha por linha que vimos até agora no prompt. E pressagia como iremos programar mais adiante: menos ênfase na execução de comandos com cada linha e mais ênfase no planejamento da funcionalidade de um programa e, em seguida, executá-lo mais tarde.
Sintaxe básica
A sintaxe para for
loops pode ser confusa, então aqui estão alguns exemplos básicos para preparar / atualizar sua compreensão deles:
Aqui “uma versão mais elaborada usando variáveis:
Uma substituição de comando pode ser usada para gerar os itens que o for
percorre em loop itera:
Se você precisar ler uma lista de linhas de um arquivo, e estão absolutamente certos de que nenhuma das linhas contém um espaço dentro deles:
Um loop de leitura durante é uma variação do anterior, mas é mais seguro para ler linhas de um arquivo:
Construindo um loop for básico
Vamos começar do começo, com um loop for
mínimo e, em seguida, construí-lo em algo mais elaborado, para nos ajudar a entender seu propósito.
O loop mais simples
Isso é tão simples como você pode fazer um loop for:
Isso parecia muito inútil? Sim, deveria. Escrevi quatro linhas de código para fazer o que uma única linha precisa fazer, echo "Hi"
.
Mais elementos na coleção
Isso “é difícil dizer, mas um” loop “foi executado. Ele apenas foi executado uma vez. OK, então como o fazemos executar mais de uma vez? Adicione mais elementos (separados por espaço) à direita de in
palavra-chave. Vamos adicionar mais quatro 1
“s:
OK, não é muito empolgante, mas o programa definitivamente parecia pelo menos em loop: quatro 1
“s resultaram em quatro echo
comandos sendo executados.
O que acontece quando substituímos esses quatro 1
“s por números diferentes? E talvez algumas palavras?
E … nada. Portanto, o loop não faz automaticamente nada específico para a coleção de valores que fornecemos. Ainda não, de qualquer maneira.
Consulte a variável de loop
Vamos olhar à esquerda da in
palavra-chave, e nessa x
. Qual é o ponto disso x
? Uma x
minúscula não é o nome de uma palavra-chave ou comando que “encontramos até agora (e executá-lo sozinho no prompt gerará um erro). Então, talvez seja uma variável? Vamos tentar referenciá-la na echo
instrução:
Bingo. Este é basicamente o funcionamento fundamental de um loop for
: – Obtenha uma coleção de itens / valores (Q Zebra 999 Smithsonian
) – Transmita-os para um for
construção de loop- Usando a variável de loop (x
) como um espaço reservado, escreva comandos entre do
/ done
bloco.- Quando o loop é executado, a variável do loop, x
, obtém o valor de cada um dos itens em a lista – Q
, Zebra
, 999
, Smithsonian
, – e o bloco de comandos entre do
e done
é então executado. Esta sequência se repete uma vez para cada item da lista.
O bloco do
/ done
pode conter qualquer sequência de comandos, até mesmo outro for
-loop:
Loops dentro de loops é uma construção comum em programação.Na maior parte do tempo, tentarei evitar a atribuição de problemas que envolvam esse tipo de lógica, pois pode ser complicado destorcer durante a depuração.
Leia um arquivo, linha por linha, confiável com leitura enquanto
Como cat
imprime um arquivo linha por linha, o seguinte loop for parece sensato:
No entanto, a substituição do comando fará com que cat
divida as palavras por espaço. Se list-of-dirs.txt
contiver o seguinte:
A saída do loop for
será esta:
Um loop de leitura enquanto preserva as palavras dentro de uma linha:
Também podemos canalizar a partir do resultado de um comando incluindo-o entre <(
e )
:
Pipes e loops
Se você vem de outras línguas, os fluxos de dados podem não ser familiares para você . Pelo menos eles são para mim, já que a sintaxe para trabalhar com eles é muito mais direta e direta no Bash do que em Ruby ou Python.
No entanto, se você for novo em programação em qualquer linguagem, o que pode também não está claro como trabalhar com fluxos de dados é diferente de trabalhar com loops.
Por exemplo, o seguinte snippet:
– produz a mesma saída que este loop:
E dependendo do seu modelo mental das coisas, parece que em ambos os exemplos, cada palavra, por exemplo, hello
, world
, é passado por um processo de tradução (via tr
) e, em seguida, ecoado.
Pipes e filtros
Sem entrar nos fundamentos do sistema Unix, no qual um pipe opera fundamentalmente diferente de um loop aqui, deixe-me sugerir uma solução alternativa mental:
Programas que direcionam de stdin e stdout geralmente podem ser organizados como filtros, nos quais um fluxo de dados entra em um programa e sai em um formato diferente:
Para tarefas que são mais do que apenas transformar dados, de filtro em filtro, pense em usar um loop. O que pode ser uma tarefa? Dada uma lista de URLs, baixe cada um e envie por e-mail os dados baixados, com corpo e assunto personalizados:
A fonte de entrada de dados, cada URL em urls.txt
, não está realmente sendo filtrado aqui. Em vez disso, uma tarefa de várias etapas está sendo realizada para cada URL.
Canalização para leitura enquanto
Dito isso, um próprio loop pode ser implementado como apenas mais um filtro entre os filtros. Considere esta variação do loop de leitura enquanto, em que o resultado de echo | grep
é canalizado, linha por linha, para o while
loop, que imprime em stdout usando echo
, que é redirecionado para o arquivo denominado some.txt:
Esta não é uma construção que você possa precisar fazer com frequência, se necessário, mas espero que reforce o uso de tubos no Unix.
Programação menos interativa
O o uso frequente de for
loops e construções semelhantes significa que “estamos ultrapassando os bons e velhos” dias de digitação em uma linha de c comandos e executá-lo logo após pressionar Enter Não importa quantos comandos empacotemos dentro de um loop for
, nada acontece até atingirmos a done
palavra-chave.
Escreva uma vez. Em seguida, faça um loop
Com essa perda de interação linha por linha com o shell, perdemos a principal vantagem do prompt interativo: feedback imediato. E ainda temos todas as desvantagens: se cometermos um erro de digitação no início do bloco de comandos entre do
e done
, temos que começar tudo acabado.
Então, aqui está como podemos atenuar isso:
Teste seu código, um caso por vez
Um dos maiores erros que os novatos cometem com for
loops se eles acham que um for
loop resolve imediatamente o problema. Então, se o que eles precisam fazer é baixar 10.000 URLs, mas eles não podem baixar corretamente apenas um URL, eles acham que colocar seus comandos falhos em um for
loop é um passo na direção certa.
Além de ser fundamentalmente um incompreensão de um loop for
, o problema prático é que agora você está executando seu código quebrado 10.000 vezes, o que significa que você tem que esperar 10.000 vezes mais para descobrir que seu código é, infelizmente, ainda está quebrado.
Então finja que “nunca ouviu falar de for
loops. Finja que você tem que baixar todos os 10.000 URLs, um comando por vez. Você pode escrever o comando para fazer isso para a primeira URL. Que tal o segundo? Assim que estiver razoavelmente confiante de que nenhum pequeno erro de sintaxe está atrapalhando você, é hora de pensar sobre como encontrar um padrão geral para os outros 9.997 URLs.
Escreva scripts
A linha de comando interativa é ótima.Foi divertido começar e será divertido durante toda a sua carreira de computação. Mas quando você tem uma grande tarefa pela frente, envolvendo mais de dez linhas de código, é hora de colocar esse código em um script de shell. Não confie em seus dedos humanos falíveis para redigitar o código perfeitamente.
Use o nano para trabalhar em loops e salvá-los como shell scripts. Para arquivos mais longos, irei trabalhar no editor de texto do meu computador (Sublime Text) e depois carregá-lo no servidor.
Exercício com web scraping
Apenas para aterrar o sintaxe e funcionamento do loop for, aqui está o processo de pensamento de transformar uma tarefa de rotina em um loop:
Para os números de 1 a 10, use curl para baixar a entrada da Wikipedia para cada número e salve-o em um arquivo chamado “
wiki-number-(whatever the number is).html
”
A maneira antiga
Com apenas 10 URLs, poderíamos definir algumas variáveis e, em seguida, copiar e colar o comando a curl, 10 vezes, fazendo alterações em cada linha:
E adivinha? Funciona. Para 10 URLs, não é uma solução ruim e é significativamente mais rápido do que fazê-lo da maneira antiga (de seu navegador da web)
Reduzindo a repetição
Mesmo sem pensar em um loop, ainda podemos reduzir a repetição usando variáveis: a URL base, , e o nome do arquivo base nunca muda, então vamos atribuir esses valores às variáveis que pode ser reutilizado:
Aplicando o loop for
Neste ponto, simplificamos o padrão até agora para que possamos ver quão pequenas são as mudanças em cada tarefa separada. Depois de aprender sobre o for
-loop, podemos aplicá-lo sem pensar muito (também adicionamos um comando de suspensão para fazer uma pausa entre as solicitações da web)
Gerando um list
Na maioria das situações, criar um loop for é fácil; é a criação da lista que pode ser o trabalho árduo. E se quiséssemos coletar as páginas dos números de 1 a 100? Isso seria muita digitação.
Mas se deixarmos nossa preguiça ditar nosso pensamento, podemos imaginar que contar de xey parece uma tarefa inerentemente computacional. E é, e o Unix tem o utilitário seq
para isso:
Gerando uma lista de não-números para iteração
Muitas tarefas repetitivas não são tão simples quanto contar de x a y, então o problema passa a ser como gerar uma lista não linear de itens? Isso é basicamente a arte da coleta e gerenciamento de dados. Mas vamos fazer um cenário simples para nós mesmos:
Para dez das palavras de 10 letras (ou mais) que aparecem pelo menos uma vez em um título na página inicial atual do NYTimes.com, buscar a página do Wikcionário para essa palavra
Dividimos essa tarefa em duas partes:
- Buscar uma lista de dez 10 + palavras em letras de títulos de nytimes.com
- Passe essas palavras para nosso loop for
Etapa 1: usando o utilitário pup (ou analisador de HTML de linha de comando do sua escolha):
Etapa 2 (assumindo que a variável words
está sendo passada adiante):
Confira Softwa Excelente guia de re carpintaria para for-loops no Bash