Простые математические операторы в bash в цикле for
Я совершенно новичок в скриптах bash и обычно избегаю всех затрат, но мне нужно написать сценарий bash для выполнения некоторых простых вещей на удаленном кластере. У меня возникли проблемы с циклом for, который делает следующее:
for i in {1..20}
do
for j in {1..20}
do
echo (i*i + j*j ) **.5 <--- Pseudo code!
done
done
можете ли вы помочь мне с этой простой математикой? Я бросил $
везде и не может написать его должным образом. Если бы вы могли помочь мне понять, как переменные называются / назначаются в bash для циклов и ограничений интерпретации математики bash (как вы это делаете квадратный корень? Я был бы очень благодарен. Спасибо!
11 ответов
вот достойное решение:
for i in {1..20}
do
for j in {1..20}
do
echo "scale = 3; sqrt($i*$i + $j*$j)" | bc
done
done
результат должен выглядеть так:
1.414
2.236
3.162
2.236
[...etc...]
требуется арифметическое расширение $((...))
нотации, что-то вроде:
echo $((i*i + j*j))
однако bash использует только целые числа, поэтому вам может потребоваться использовать внешний инструмент, такой как dc.
Э. Г.
dc -e "18k $i $i * $j $j * + v p"
Shell math можно сделать несколькими способами.
echo $(( i*i + j*j ))
echo $[ i*i + j*j ]
expr "$i" '*' "$i" '+' "$j" '*' "$j"
однако это может обрабатывать только целочисленную арифметику. Вместо этого, вы можете использовать bc
:
echo "scale = 5; sqrt( $i*$i + $j*$j)" | bc
изменить scale
число десятичных знаков желаемой.
у вашего удаленного кластера есть только bash? если нет, попробуйте и посмотрите, есть ли у вас awk
awk 'BEGIN{
for(i=1;i<=20;i++){
for(j=1;j<=20;j++){
print ( i*i + j*j ) ** 0.5
}
}
}'
используйте double paren для оценки переменной.
variableA=$((variableB*variableC))
только для ints, хотя.
обычно вы используете $((1*3)), но ваш случай не будет работать, поскольку bash не поддерживает числа с плавающей запятой. Вам придется использовать внешний инструмент, такой как awk, bc или dc: http://mywiki.wooledge.org/BashFAQ/022
код
echo $[(($i * $i) + ($j * $j)) ** $X]
будет работать, если $X
- целое число. Вы пытаетесь взять квадратный корень, и я не уверен, что встроенная арифметика Баша сделает это. Вероятно, вам будет лучше использовать более мощный инструмент калькулятора (например,bc
, et al.) для этого.
Bash не предлагает математических функций. Тем не менее, у вас почти наверняка установлена оболочка korn. Это должно сработать:
#!/bin/ksh
for i in {1..20}
do
for j in {1..20}
do
x=$((sqrt(i*i + j*j)))
echo "sqrt($i^2 + $j^2) = $x"
done
done
начало вывода -
sqrt(1^2 + 1^2) = 1.41421356237309505
sqrt(1^2 + 2^2) = 2.2360679774997897
sqrt(1^2 + 3^2) = 3.16227766016837933
sqrt(1^2 + 4^2) = 4.12310562561766055
sqrt(1^2 + 5^2) = 5.09901951359278483
sqrt(1^2 + 6^2) = 6.08276253029821969
sqrt(1^2 + 7^2) = 7.07106781186547524
sqrt(1^2 + 8^2) = 8.06225774829854965
sqrt(1^2 + 9^2) = 9.05538513813741663
sqrt(1^2 + 10^2) = 10.0498756211208903
С zsh это будет работать
for i in {1..20};do
for j in {1..20};do
echo $((($i*$i + $j*$j)**.5))
done
done
другая форма целочисленных математических выражений в Bash ставит двойные скобки снаружи всего выражения для операций присваивания:
(( var = i ** 2 ))
(( i++ ))
(( position += delta ))
как вы можете видеть, знаки доллара здесь не нужны (ни внутри $(())
). Кроме того, допускаются пробелы вокруг знака равенства.
кроме того, эта форма может использоваться в conditionals:
sixpacks=8 # note spaces not allowed here
(( beerprice = 8 )) # but you can use spaces this way
budget=50
# you can do assignments inside a conditional just like C
until (( (( beertotal = sixpacks * beerprice )) <= budget ))
do
(( sixpacks-- ))
done
echo "Buy ${sixpacks} six-packs at $${beerprice} each for a total of $${beertotal}."
или вы можете заменить все это на это, конечно:
beerprice=8
budget=50
# integer division
(( sixpacks = budget / beerprice ))
(( beertotal = sixpacks * beerprice ))
echo "Buy ${sixpacks} six-packs at $${beerprice} each for a total of $${beertotal}."
Bash также имеет let
заявление:
let a=2**16
let 'a>>=1' # bitwise shift - some operations need to be quoted or escaped
(( a>>=1 )) # but not inside (())