Come posso creare un ciclo aritmetico in uno script shell POSIX?


12

So come creare un forloop aritmetico bash.

Come si può fare un ciclo equivalente in uno script shell POSIX?

Dato che ci sono vari modi per raggiungere lo stesso obiettivo, sentiti libero di aggiungere la tua risposta ed elaborare un po 'su come funziona.

Segue un esempio di uno di questi bashloop:

#!/bin/bash
for (( i=1; i != 10; i++ ))
do
    echo "$i"
done

@ StéphaneChazelas perché era una nota sulla storia che sembrava essere basata su un malinteso poiché l'OP non stava suggerendo che fosse una cosa bash, ma semplicemente usando bash come esempio. Non sembrava davvero rilevante.
terdon

Risposte:


13

Ho trovato informazioni utili nel wiki Shellcheck.net , cito:

  1. bash:

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

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

ma attenzione che i++non è POSIX quindi dovrebbe essere tradotto, ad esempio in i += 1o i = i + 1.


Quindi lo script sopra nella domanda può essere riscritto in POSIX usando quelle regole come questa:

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

Sebbene qui, puoi renderlo più leggibile con:

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

come in init, stiamo assegnando un valore costante, quindi non abbiamo bisogno di valutare un'espressione aritmetica. L' i != 10In testpuò essere facilmente tradotto in [un'espressione e per next, usando un'assegnazione variabile di shell invece di un'assegnazione variabile all'interno di un'espressione aritmetica, ci liberiamo di :e la necessità di quotare.


Oltre a i++-> i = i + 1, ci sono più traduzioni di costrutti specifici di ksh / bash che non sono POSIX che potresti dover fare:

  • i=1, j=2. L' ,operatore aritmetico non è realmente POSIX (e è in conflitto con il separatore decimale in alcune versioni locali con ksh93). Potresti sostituirlo con un altro operatore come +in : "$(((i=1) + (j=2)))"ma l'utilizzo i=1 j=2sarebbe molto più leggibile.
  • a[0]=1: nessuna matrice nelle shell POSIX
  • i = 2**20: nessun operatore di potenza nella sintassi della shell POSIX. <<è supportato anche se così per potenze di due, si può usare i = 1 << 20. Per altri poteri, si può ricorrere a bc:i=$(echo "3 ^ 20" | bc)
  • i = RANDOM % 3: non POSIX. Il più vicino al toolchest POSIX è i=$(awk 'BEGIN{srand(); print int(rand() * 3)}').

2

grazie per la conoscenza approfondita della differenza. Un calo nella sostituzione che funziona per me quando utilizzo shellcheck.net era il seguente.

BASH

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

POSIX

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

alcune persone hanno notato che seq è anche un'opzione che utilizza seq 1 10. Creazione di un ciclo, tuttavia questo dipende dal fatto che os abbia seq.


nota che ho inserito i = 0 nella stessa riga di while. anche se la leggibilità non è eccezionale, è un drop-in di una riga. Questo assicura che la variabile i non sia contaminata da nessun'altra parte definita nello script.
Jimmy MG Lim,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.