Mnożenie i dodawanie Bash

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

Cześć, potrzebuję uproszczonego wyrażenia dla trzeciego wiersza, być może takiego, który nie korzysta z podstawiania poleceń.

AVS
źródło
@Theophrastus: Jak sugeruje, działa dobrze, ale co jeśli chciałbym użyć wyraż zamiast zamiast (()).
AVS
Tak jest bashi nie C, więc usuń wszystko ;- chyba że napiszesz to w osobnej linii.
ott--
Zobacz także: 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
Poza tym: $(( ... ))czy interpretacja arytmetyczna nie zastępuje poleceń.
dave_thompson_085

Odpowiedzi:

28

Korzystanie z rozszerzania arytmetycznego:

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

Korzystanie z przestarzałego exprnarzędzia:

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

Używanie bc -l( -lw tym przypadku nie jest potrzebne, ponieważ nie są używane żadne funkcje matematyczne):

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

Używając bc -ljako koproces (działa w tle jako rodzaj usługi obliczeniowej w tle¹):

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"

Ten ostatni wygląda (prawdopodobnie) na czystszy w 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"

¹ Rozwiązało to kiedyś problem, w którym musiałem przetworzyć dużą ilość danych wejściowych w pętli. Przetwarzanie wymagało pewnych obliczeń zmiennoprzecinkowych, ale bckilka razy odradzanie się w pętli okazało się wyjątkowo wolne. Tak, mogłem to rozwiązać na wiele innych sposobów, ale nudziłem się ...

Kusalananda
źródło
12

Możesz uprościć:

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

do:

a=$((2*k+1))
Jeff Schaller
źródło
5

Możesz użyć letpolecenia, aby wymusić obliczenia.

let a="2*k+1"

Zauważ, że nie potrzebujemy $kw tej strukturze; prosty kwykona zadanie.

Stephen Harris
źródło
4
To się nie powiedzie, jeśli a=2whateverk+1w bieżącym katalogu znajduje się plik . Gorzej, jeśli istnieje plik o nazwie a=2+b[$(reboot)]k+1, który wywołuje rebootpolecenie. Najlepiej jest użyć ((...))tutaj ( ((a = 2 * k + 1))) lub składni POSIX:a=$((2 * k + 1))
Stéphane Chazelas
Możemy to zacytować; let a="2*k+1"rozwiązać to.
Stephen Harris
2

Rozbudowa arytmetyczna, której prawdopodobnie potrzebujesz, jest następująca:

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

W rzeczywistości nie musisz używać zmiennej:

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

Lub zmienną zliczającą można przenieść do for ((…))pętli:

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

dla pętli

W takim przypadku rozszerzenie arytmetyczne można również przenieść do wewnątrz pętli for:

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

Lub, aby uzyskać wszystkie wartości w tablicy:

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

Bez formuły

Ale prawdopodobnie najkrótszym sposobem uniknięcia ekspansji arytmetycznej jest dwukrotne zwiększenie zmiennej:

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

Lub, jeszcze prościej, po prostu użyj seq:

seq 1 2 100

źródło