Bash multiplicación y suma

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

Hola, necesito una expresión simplificada para la tercera línea, tal vez una que no use la sustitución de comandos.

AVS
fuente
@Theophrastus: Como se sugirió, funciona bien, pero ¿y si quisiera usar expr en lugar de (())?
AVS
Esto es bashy no C, así que elimine todo ;, a menos que lo escriba en una línea singular.
ott--
Ver también: unix.stackexchange.com/q/40786/117549
Jeff Schaller
declare -i a; for k in {0..49}; do a=2*$k+1; echo $a; done
Cyrus
1
Aparte: $(( ... ))es la expansión aritmética, no la sustitución de comandos.
dave_thompson_085

Respuestas:

27

Usando la expansión aritmética:

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

Usando la exprutilidad anticuada :

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

Uso bc -l(en -lrealidad no es necesario en este caso, ya que no se utilizan funciones matemáticas):

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

Utilizando bc -lcomo un coproceso (actúa como una especie de servicio de computación en segundo plano¹):

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"

Ese último se ve (posiblemente) más limpio en 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"

¹ Esto resolvió un problema para mí una vez donde necesitaba procesar una gran cantidad de entrada en un bucle. El procesamiento requirió algunos cálculos de coma flotante, pero el desove bcalgunas veces en el ciclo resultó ser extremadamente lento. Sí, podría haberlo resuelto de muchas otras maneras, pero estaba aburrido ...

Kusalananda
fuente
12

Puedes simplificar:

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

a:

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

Puede usar el letcomando para forzar un cálculo.

let a="2*k+1"

Tenga en cuenta que no necesitamos $ken esta estructura; Un simple khará el trabajo.

Stephen Harris
fuente
44
Eso falla si hay un archivo llamado a=2whateverk+1en el directorio actual. Peor aún, si hay un archivo llamado a=2+b[$(reboot)]k+1, eso llama al rebootcomando. Lo mejor es usar ((...))aquí ( ((a = 2 * k + 1))), o la sintaxis POSIX:a=$((2 * k + 1))
Stéphane Chazelas
Podemos citarlo; let a="2*k+1"para resolver eso
Stephen Harris
2

La expansión aritmética que probablemente necesite es esta:

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

De hecho, no necesita usar una variable:

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

O la variable de conteo podría moverse a un for ((…))ciclo:

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

en bucle

Y, en ese caso, la expansión aritmética también podría moverse dentro del ciclo for:

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

O, para obtener todos los valores en una matriz:

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

Sin formula

Pero probablemente la forma más corta de evitar cualquier expansión aritmética es incrementar una variable dos veces:

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

O, incluso más simple, simplemente use seq:

seq 1 2 100

fuente