Умножение и сложение Баш

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

Привет, мне нужно упрощенное выражение для третьей строки, возможно, такое, которое не использует подстановку команд.

AVS
источник
@Theophrastus: Как и предполагалось, он работает нормально, но что, если я хотел бы использовать expr вместо (()).
AVS
Это bashи не Cтак, поэтому удалите все ;- если вы не пишете это в единственной строке.
ot--
См. Также: unix.stackexchange.com/q/40786/117549
Джефф Шаллер
declare -i a; for k in {0..49}; do a=2*$k+1; echo $a; done
Сайрус
1
В сторону: $(( ... ))это арифметическое расширение, а не подстановка команд.
dave_thompson_085

Ответы:

27

Используя арифметическое расширение:

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

Используя устаревшую exprутилиту:

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

Использование bc -l(на -lсамом деле не нужно в этом случае, так как математические функции не используются):

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

Использование bc -lв качестве совместного процесса (он действует как своего рода вычислительная служба в фоновом режиме¹):

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"

Этот последний выглядит (возможно) чище в 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"

Once Это однажды решило проблему для меня, когда мне нужно было обработать большое количество входных данных в цикле. Обработка требовала некоторых вычислений с плавающей запятой, но порождение bcв цикле несколько раз оказалось чрезвычайно медленным. Да, я мог бы решить это многими другими способами, но мне было скучно ...

Кусалананда
источник
12

Вы можете упростить:

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

чтобы:

a=$((2*k+1))
Джефф Шаллер
источник
5

Вы можете использовать letкоманду для принудительного расчета.

let a="2*k+1"

Обратите внимание, что нам не нужна $kэта структура; простой kсделает работу.

Стивен Харрис
источник
4
Это не удастся, если a=2whateverk+1в текущем каталоге будет вызван файл . Хуже того, если есть файл a=2+b[$(reboot)]k+1, который вызывает rebootкоманду. Лучше всего использовать ((...))здесь ( ((a = 2 * k + 1))) или синтаксис POSIX:a=$((2 * k + 1))
Стефан Шазелас
Мы можем процитировать это; let a="2*k+1"чтобы решить это.
Стивен Харрис
2

Арифметическое расширение, которое вам, вероятно, нужно:

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

На самом деле вам не нужно использовать переменную:

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

Или переменная подсчета может быть перемещена в for ((…))цикл:

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

для ((…)) цикла

И, в этом случае, арифметическое расширение также может быть перемещено внутрь цикла for:

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

Или, чтобы получить все значения в массиве:

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

Нет формулы

Но, вероятно, самый короткий способ избежать арифметического расширения - это увеличить переменную дважды:

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

Или, что еще проще, просто используйте seq:

seq 1 2 100

источник