Como posso criar um script para contar por cinco?

10

Eu estava tentando fazer um script muito simples para listar todos os múltiplos de cinco entre 375 e 3500 (375, 380, 385 ...). Uma coisa que eu tentei e não funcionou é:

for i in {375..3500}
do
        echo $i
        (($i += 5))
done

Eu desisti depois de um tempo e escrevi isso no BASIC em aproximadamente 15 segundos:

10 count = 375
20 print count
30 count = count+5
40 if count < 3500 then goto 20

Como posso fazer meu programa BASIC em um script bash?

    
por aswine 23.07.2015 / 17:22

7 respostas

20

Alternativamente, um loop de estilo C tradicional pode ser usado:

for ((i=375; i<=3500; i+=5)); do
    echo $i
done

Isso talvez seja menos claro do que usar seq, mas não gera nenhum subprocesso. Embora desde que eu esteja familiarizado com C, eu não teria nenhuma dificuldade em entender isso, mas YMMV.

    
por 23.07.2015 / 17:30
26

Como você usa a expansão de chaves de qualquer maneira, use o recurso:

echo {375..3500..5}

Você também pode usar essa técnica para imprimir cada número em uma linha separada com texto opcional usando printf em vez de echo , por exemplo:

$ printf "Number %s is generated.\n" {375..3500..5}
Number 375 is generated.
Number 380 is generated.
Number 385 is generated.
...

Editar

Como apontado por @kojiro no comentário, o Mac OS usa o bash 3 como o shell padrão, que não suporta incrementos na expressão de seqüência da expansão de chaves. Você precisa atualizar para o bash versão 4 ou usar outro shell que suporte isso (por exemplo, zsh recente).

    
por 23.07.2015 / 17:47
17

Usando SEQ (1)

for i in $(seq 375 5 3500)
do
    echo $i
done

Ou simplesmente:

seq 375 5 3500
    
por 23.07.2015 / 17:25
11

Seu snippet for-loop não funcionou conforme o necessário por dois motivos:

  • (($i += 5)) - aqui o $i é expandido para o valor de i . Assim, a expansão será algo como ((375 += 5)) , o que não faz sentido (tentar atribuir um número literal a outro número literal). Isso normalmente seria obtido com ((i += 5)) (sem $ para expandir a variável)
  • O {375..3500} será expandido antes da primeira iteração do loop. Será a lista de números 375 376 ... 3499 3500 . Para cada iteração do loop, i será atribuído a cada um desses números, um por um. Assim, no início de cada iteração, i será reatribuído ao próximo valor nessa lista, contando-se em etapas de 1. O ((i += 5)) efetivamente não faz nada - ele adiciona 5 a i, mas, em seguida, eu apenas reatribuo novamente no início da próxima iteração.

Acho que gostei mais da resposta for (( ; ; )) , mas aqui estão algumas alternativas para você pensar:

Como estamos lidando com múltiplos de 5, e a expansão {a..b..i} não é suportada na versão bash 3.2.57 (1) (no OS X), então podemos fazer essa coisa um pouco misteriosa:

for i in 375 {38..349}{0,5} 3500; do
    echo $i
done

Isso demonstra como o bash pode ser usado para criar um produto cartesiano.

Eu acho que em geral um loop for é a maneira mais conveniente de fazer isso, mas se você estiver interessado, você pode usar um programa while-loop (um pouco mais próximo do seu BASIC):

count=375
while (( count <= 3500 )); do
    echo $count
    (( count += 5 ))
done
    
por 23.07.2015 / 22:09
5

Embora exista, é claro, um aplicativo para isso ( seq 375 5 3500 ), existem várias maneiras de fazer isso a partir da linha de comando. Embora o mais rápido e simples seja usar apenas seq , aqui estão algumas outras opções:

for i in {375..3500}; do [[ (($i % 5)) -eq 0 ]] && echo $i; done

i=370; while [ $i -le 3500 ]; do printf "%s\n" $((i+=5)); done

perl -le '$i=shift;while($i<=$ARGV[0]){print $i; $i+=5; }' 375 3500
perl -le 'map{print $_ + 5} 370..3495'

awk 'BEGIN{ for(i=375;i<=3500;i+=5){print i}}'
    
por 23.07.2015 / 20:09
4

POSIXly:

i=370
while [ 3500 -gt "$i" ]
do    echo "$((i+=5))"
done

... ou ...

echo 'for(x=370;x<=3500;x+=5)x' |bc

Eu não sei por que você faria de outra maneira. Exceto, claro ...

seq 375 5 3500

... ou com dc :

echo '370[5+pd3500>p]splpx'|dc
    
por 24.07.2015 / 02:43
3

Se você está preso no Bash 3:

echo {375..3500} | tr ' ' '\n' | sed -n 'p;n;n;n;n'

e se você preferir awk :

echo {375..3500} | tr ' ' '\n' | awk '!((NR-1)%5)'

Eu não sabia sobre a expansão de chaves - isso é muito legal.

    
por 25.07.2015 / 18:19