Como faço para escrever um loop for no bash

Respostas:

103

Deste site :

for i in $(seq 1 10);
do
    echo $i
done
Rob Rolnick
fonte
10
Vale ressaltar que o intervalo aqui especificado é inclusivo . Com isso, quero dizer que você verá todo o intervalo (1 a 10) impresso no console.
Jamie
62
for ((i = 0 ; i < max ; i++ )); do echo "$i"; done
Nick Stinemates
fonte
se tivermos uma variável como ArrayLength=${#array[@]}como usamos aqui em vez de max?
Kasun Siyambalapitiya
34

O bash forconsiste em uma variável (o iterador) e uma lista de palavras onde o iterador irá, bem, iterar.

Portanto, se você tiver uma lista limitada de palavras, basta colocá-las na seguinte sintaxe:

for w in word1 word2 word3
do
  doSomething($w)
done

Provavelmente você deseja iterar ao longo de alguns números, então você pode usar o seqcomando para gerar uma lista de números para você: (de 1 a 100, por exemplo)

seq 1 100

e usá-lo no loop FOR:

for n in $(seq 1 100)
do
  doSomething($n)
done

Observe a $(...)sintaxe. É um comportamento bash, permite que você passe a saída de um comando (no nosso caso de seq) para outro (o for)

Isso é muito útil quando você precisa iterar sobre todos os diretórios em algum caminho, por exemplo:

for d in $(find $somepath -type d)
do
  doSomething($d)
done

As possibilidades são infinitas para gerar as listas.

Fernando Barrocal
fonte
2
Boa resposta, mas você pode querer incluir o for ((i = 0; i <MAX; i ++)); faça doSomething ($ i); variante feita também. Eu acho que geralmente é preferível a variante for i in $ (seq 0 MAX), pois a última irá primeiro gerar todos os números de 0 a MAX antes de realmente executar o loop.
mweerden,
30

O Bash 3.0+ pode usar esta sintaxe:

for i in {1..10} ; do ... ; done

..que evita gerar um programa externo para expandir a sequência (como seq 1 10).

Claro, isso tem o mesmo problema da for(())solução, estar vinculado ao bash e até mesmo a uma versão específica (se isso for importante para você).

David Gardner
fonte
14

Experimente a bashajuda integrada:


$ help for

for: for NAME [in WORDS ... ;] do COMMANDS; done
    The `for' loop executes a sequence of commands for each member in a
    list of items.  If `in WORDS ...;' is not present, then `in "$@"' is
    assumed.  For each element in WORDS, NAME is set to that element, and
    the COMMANDS are executed.
for ((: for (( exp1; exp2; exp3 )); do COMMANDS; done
    Equivalent to
        (( EXP1 ))
        while (( EXP2 )); do
            COMMANDS
            (( EXP3 ))
        done
    EXP1, EXP2, and EXP3 are arithmetic expressions.  If any expression is
    omitted, it behaves as if it evaluates to 1.


Pat Notz
fonte
5
#! /bin/bash

function do_something {
   echo value=${1}
}

MAX=4
for (( i=0; i<MAX; i++ )) ; {
   do_something ${i}
}

Aqui está um exemplo que também pode funcionar em shells mais antigos, embora seja eficiente para grandes contagens:

Z=$(date) awk 'BEGIN { for ( i=0; i<4; i++ ) { print i,"hello",ENVIRON["Z"]; } }'

Mas boa sorte fazendo coisas úteis dentro de awk: Como faço para usar variáveis ​​de shell em um script awk?

Brent Bradburn
fonte
2
Eu não percebi isso antes, mas uma sintaxe semelhante é mostrada em uma das respostas anteriores. A única coisa aqui é o uso de chaves em vez do par típico do/ done.
Brent Bradburn
4

Normalmente gosto de usar uma ligeira variante no padrão para loop. Costumo usar isso para executar um comando em uma série de hosts remotos. Aproveito a expansão da chave do bash para criar loops for que me permitem criar loops for não numéricos.

Exemplo:

Quero executar o comando uptime nos hosts de front-end 1-5 e nos hosts de back-end 1-3:

% for host in {frontend{1..5},backend{1..3}}.mycompany.com
    do ssh $host "echo -n $host; uptime"
  done

Normalmente, executo isso como um comando de linha única com ponto-e-vírgula no final das linhas, em vez da versão mais legível acima. A principal consideração de uso é que os colchetes permitem que você especifique vários valores a serem inseridos em uma string (por exemplo, pré {foo, bar} resultados de pós em prefoopost, pré-barra) e permite a contagem / sequências usando os pontos duplos (você pode usar um. .z etc.). No entanto, a sintaxe de período duplo é um novo recurso do bash 3.0; versões anteriores não suportam isso.

Terson
fonte
Relacionado a isso, e se $ host var for uma linha vazia por algum acidente? Ainda iria disparar ssh. Então, como faço para evitar isso? No meu caso estou fazendo algo diferente e sua resposta vai me ajudar. Estou tentando verificar se há novas mensagens no Gmail e, se forem encontradas, envio um SMS de de e assunto. Minha pergunta se chama "Conectando dois comandos Bash" se você quiser lê-la.
Volomike
Não acredito que você receba um $ host var vazio. Isso ocorre porque o exemplo acima está usando a expansão de chaves. O loop for define explicitamente a variável $ host para os valores: frontend1.mycompany.com frontend2.mycompany.com. . backend1.mycompany.com Mas se você vir uma maneira de ter um valor nulo; Eu estaria interessado em saber. Você poderia executar o ssh dentro de um teste condicional se fosse uma preocupação.
terson
1

se você está interessado apenas em bash a solução "for ((...))" apresentada acima é a melhor, mas se você quiser algo compatível com POSIX SH que funcione em todos os unices você terá que usar "expr" e "while", e isso porque "(())" ou "seq" ou "i = i + 1" não são tão portáteis entre vários shells


fonte
0

Eu uso variações disso o tempo todo para processar arquivos ...

para arquivos em * .log; do echo "Fazer coisas com: $ arquivos"; echo "Faça mais coisas com: $ arquivos"; feito;

Se você estiver interessado em processar listas de arquivos, procure a opção -execdir para arquivos .


fonte
Acho que você quer dizer opção -execdir para localizar
Pausado até novo aviso.