web-dev-qa-db-fra.com

Multiplication et addition de Bash

for k in {0..49};
do
a=$(($((2*$k))+1));
echo $a;
done

Salut, j'ai besoin d'une expression simplifiée pour la troisième ligne, peut-être celle qui n'utilise pas de substitution de commande.

20
AVS

Utilisation de l'expansion arithmétique:

for (( k = 0; k < 50; ++k )); do
  a=$(( 2*k + 1 ))
  echo "$a"
done

Utilisation de l'utilitaire expr désuet:

for (( k = 0; k < 50; ++k )); do
  a=$( expr 2 '*' "$k" + 1 )
  echo "$a"
done

En utilisant bc -l (-l pas réellement nécessaire dans ce cas car aucune fonction mathématique n'est utilisée):

for (( k = 0; k < 50; ++k )); do
  a=$( bc -l <<<"2*$k + 1" )
  echo "$a"
done

En utilisant bc -l comme un co-processus (il agit comme une sorte de service de calcul en arrière-plan¹):

coproc bc -l

for (( k = 0; k < 50; ++k )); do
  printf "2*%d + 1\n" "$k" >&${COPROC[1]}
  read -u "${COPROC[0]}" a
  echo "$a"
done

kill "$COPROC_PID"

Ce dernier semble (sans doute) plus propre dans ksh93:

bc -l |&
bc_pid="$!"

for (( k = 0; k < 50; ++k )); do
  print -p "2*$k + 1"
  read -p a
  print "$a"
done

kill "$bc_pid"

¹ Cela a résolu un problème pour moi une fois où je devais traiter une grande quantité d'entrée dans une boucle. Le traitement a nécessité quelques calculs en virgule flottante, mais la génération de bc plusieurs fois dans la boucle s'est avérée extrêmement lente. Oui, j'aurais pu le résoudre de bien d'autres façons, mais je m'ennuyais ...

32
Kusalananda

Vous pouvez simplifier:

a=$(($((2*$k))+1));

à:

a=$((2*k+1))
14
Jeff Schaller

Vous pouvez utiliser la commande let pour forcer un calcul.

let a="2*k+1"

Notez que nous n'avons pas besoin de $k dans cette structure; un simple k fera le travail.

5
Stephen Harris

L'expansion arithmétique dont vous avez probablement besoin est la suivante:

a=$(( 1+2*k ))

En fait, vous n'avez pas besoin d'utiliser une variable:

for k in {0..49}; do
    echo "$(( 1 + 2*k ))"
done

Ou la variable de comptage pourrait être déplacée vers une boucle for ((…)):

for (( k=0;k<50;k++ )); do
    a=$(( 1+2*k ))
    printf '%s\n' "$a"
done

pour ((…)) boucle

Et, dans ce cas, l'expansion arithmétique pourrait également être déplacée à l'intérieur de la boucle for:

for (( k=0 ; a=1+2*k , k<50 ;  k++)); do
    printf '%s\n' "$a"
done

Ou, pour obtenir toutes les valeurs d'un tableau:

for (( k=0 ; a[k]=1+2*k , k<49 ;  k++ )); do :; done
printf '%s\n' "${a[@]}"

Pas de formule

Mais le moyen le plus court d'éviter toute expansion arithmétique est probablement d'incrémenter une variable deux fois:

for (( k=0,a=1 ; k<50 ;  k++,a++,a++ )); do
    printf '%s\n' "$a"
done

Ou, encore plus simple, utilisez simplement seq:

seq 1 2 100
2
user79743