Multiplicação e adição de bash

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

Oi, preciso de uma expressão simplificada para a terceira linha, talvez uma que não use substituição de comando.

AVS
fonte
@ Theophrastus: Como sugerido, funciona bem, mas e se eu quisesse usar expr em vez de (()).
AVS
Isso é bashe não C, então remova tudo ;- a menos que você o escreva em uma linha singular.
30--16
Veja também: 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
Além: a $(( ... ))expansão aritmética não comanda a substituição.
David_thompson_085

Respostas:

27

Usando expansão aritmética:

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

Usando o exprutilitário antiquado :

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

Usando bc -l( -lnão é realmente necessário neste caso, pois nenhuma função matemática é usada):

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

Usando bc -lcomo um co-processo (ele age como uma espécie de serviço de computação em 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"

Esse último parece (sem dúvida) mais limpo em 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"

¹ Isso resolveu um problema para mim uma vez em que eu precisava processar uma grande quantidade de entrada em um loop. O processamento exigiu alguns cálculos de ponto flutuante, mas a geração bcalgumas vezes no loop se mostrou extremamente lenta. Sim, eu poderia ter resolvido isso de muitas outras maneiras, mas estava entediado ...

Kusalananda
fonte
12

Você pode simplificar:

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

para:

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

Você pode usar o letcomando para forçar um cálculo.

let a="2*k+1"

Observe que não precisamos $kdessa estrutura; um simples kfará o trabalho.

Stephen Harris
fonte
4
Isso falhará se houver um arquivo chamado a=2whateverk+1no diretório atual. Pior, se houver um arquivo chamado a=2+b[$(reboot)]k+1, que chama o rebootcomando. O melhor é usar ((...))aqui ( ((a = 2 * k + 1))), ou a sintaxe do POSIX:a=$((2 * k + 1))
Stéphane Chazelas
Podemos citá-lo; let a="2*k+1"para resolver isso.
Stephen Harris
2

A expansão aritmética de que você provavelmente precisa é esta:

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

De fato, você não precisa usar uma variável:

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

Ou a variável de contagem pode ser movida para um for ((…))loop:

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

loop for ((…))

E, nesse caso, a expansão aritmética também pode ser movida para dentro do loop for:

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

Ou, para obter todos os valores em uma matriz:

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

Nenhuma fórmula

Mas provavelmente a maneira mais curta de evitar qualquer expansão aritmética é incrementar uma variável duas vezes:

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

Ou, ainda mais simples, basta usar seq:

seq 1 2 100

fonte