Como posso criar um loop aritmético em um script de shell POSIX?

6

Eu sei como criar um loop for aritmético em bash .

Como se pode fazer um loop equivalente em um script de shell POSIX?

Como existem várias maneiras de alcançar o mesmo objetivo, sinta-se à vontade para adicionar sua própria resposta e elaborar um pouco sobre como ela funciona.

Um exemplo de um loop de bash é o seguinte:

#!/bin/bash
for (( i=1; i != 10; i++ ))
do
    echo "$i"
done
    
por Vlastimil 13.12.2017 / 14:10

2 respostas

7

Encontrei informações úteis no wiki do Shellcheck.net , e cito:

  1. Bash:

    for ((init; test; next)); do foo; done
    
  2. POSIX:

    : "$((init))"
    while [ "$((test))" -ne 0 ]; do foo; : "$((next))"; done
    

embora tenha cuidado, pois i++ não é POSIX então teria que ser traduzido, por exemplo para i += 1 ou i = i + 1 .

Assim, o script acima na pergunta pode ser reescrito no POSIX usando as regras como esta:

#!/bin/sh
: "$((i=1))"
while [ "$((i != 0))" -ne 0 ]
do
    echo "$i"
    : "$((i = i + 1))"
done

Embora esteja aqui, você pode torná-lo mais legível com:

#!/bin/sh
i=1
while [ "$i" -ne 10 ]
do
    echo "$i"
    i=$((i + 1))
done

como em init , estamos atribuindo um valor constante, portanto, não precisamos avaliar uma expressão aritmética. O i != 10 in test pode ser facilmente traduzido para uma expressão [ , e para next , usando uma atribuição de variável shell ao contrário de uma atribuição variável dentro de uma expressão aritmética, nos permite eliminar : e a necessidade de citar.

Ao lado de i++ - > i = i + 1 , existem mais traduções de construções específicas do ksh / bash que não são POSIX que você possa ter que fazer:

  • %código%. O operador de aritmética i=1, j=2 não é realmente POSIX (e entra em conflito com o separador decimal em algumas localidades com ksh93). Você poderia substituí-lo por outro operador como , como em + , mas usar : "$(((i=1) + (j=2)))" seria muito mais legível.
  • i=1 j=2 : sem matrizes em shells POSIX
  • a[0]=1 : no power operator na sintaxe do shell POSIX. i = 2**20 é suportado, portanto, para potências de dois, pode-se usar << . Para outros poderes, pode-se recorrer a i = 1 << 20 : bc
  • i=$(echo "3 ^ 20" | bc) : não POSIX. O mais próximo do toolkit de POSIX é i = RANDOM % 3 .
por 13.12.2017 / 14:10
1

obrigado pelo conhecimento acima profundo sobre a diferença. Uma queda no substituto que funcionou para mim ao usar o shellcheck.net foi a seguinte.

BASH

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

POSIX

i=0; while [ $i -le 100 ]; do  
  ...  
  i=$(( i + 1 ))  
done

algumas pessoas notaram que seq também é uma opção usando seq 1 10. Criando um loop, no entanto, isso depende que o os seq.

    
por 20.05.2018 / 00:48