Как я могу сделать деление с переменными в оболочке Linux?


136

Когда я запускаю команды в своей оболочке, как показано ниже, она возвращает expr: non-integer argumentошибку. Может кто-нибудь, пожалуйста, объясните мне это?

$ x=20
$ y=5
$ expr x / y 
expr: non-integer argument

4
@ShivanRaptor Хотя можно утверждать, что этот вопрос является вопросом RTFM, он, безусловно, является актуальным вопросом программирования оболочки. Это также разумный вопрос для тех, кто пришел из языков, которые не требуют разыменования (например, Ruby или JavaScript). Это должно быть оставлено открытым.
Тодд А. Джейкобс

6
@ShivanRaptor Нет, это по теме здесь. Это о программировании на Bash. Unix / Linux в первую очередь для использования системы, а не программирования. Теперь сценарии оболочки охватывают границу между программированием и использованием системы, так что это может быть тема на любом сайте. Если бы возник вопрос о том, «как настроить сеть», это определенно относится к Unix / Linux. Если бы это был вопрос об интерактивных сочетаниях клавиш в Bash, он бы тоже был там. Но вопрос о сценариях оболочки определенно стоит здесь и там.
Брайан Кэмпбелл

Смотрите мой ответ здесь, который иллюстрирует вычитание и деление переменных $ BASH, используя вызов Python из оболочки (для преобразования int в float ...): stackoverflow.com/questions/8385627/…
Виктория Стюарт

Ответы:


195

Эти переменные являются переменными оболочки. Чтобы расширить их как параметры для другой программы ( т.е. expr ), вам нужно использовать $префикс:

expr $x / $y

Причина, по которой он жаловался, заключается в том, что он думал, что вы пытаетесь оперировать буквенными символами ( т.е. не целыми числами)

Если вы используете оболочку Bash, вы можете достичь того же результата, используя синтаксис выражения:

echo $((x / y))

Или:

z=$((x / y))
echo $z

1
Вы можете многое узнать, прочитав man-страницу bash. Введите man bashв командной строке ( qдля выхода)
Пэдди

62
Где-то на этой странице нужно отметить, что большинство (если не все) оболочек GNU / Linux выполняют только целочисленные операции .
Скиппи ле Гран Гуру

35

Я считаю, что это уже упоминалось в других темах:

calc(){ awk "BEGIN { print "$*" }"; }

тогда вы можете просто набрать:

calc 7.5/3.2
  2.34375

В вашем случае это будет:

x=20; y=3;
calc $x/$y

или, если хотите, добавьте его как отдельный скрипт и сделайте его доступным в $ PATH, чтобы он всегда был в локальной оболочке:

#!/bin/bash
calc(){ awk "BEGIN { print $* }"; }

4
Вы также можете использоватьecho '1 / 3' | bc -l
Евгений

19

Почему бы не использовать let; Я нахожу это намного проще. Вот пример, который вы можете найти полезным:

start=`date +%s`
# ... do something that takes a while ...
sleep 71

end=`date +%s`
let deltatime=end-start
let hours=deltatime/3600
let minutes=(deltatime/60)%60
let seconds=deltatime%60
printf "Time spent: %d:%02d:%02d\n" $hours $minutes $seconds

Еще один простой пример - подсчитать количество дней с 1970 года:

let days=$(date +%s)/86400

15

Ссылка на переменные Bash требует расширения параметров

Оболочкой по умолчанию в большинстве дистрибутивов Linux является Bash. В Bash переменные должны использовать префикс знака доллара для расширения параметров . Например:

x=20
y=5
expr $x / $y

Конечно, Bash также имеет арифметические операторы и специальный синтаксис арифметического расширения , поэтому нет необходимости вызывать двоичный файл expr как отдельный процесс. Вы можете позволить оболочке выполнять всю работу следующим образом:

x=20; y=5
echo $((x / y))

См. Арифметическое расширение и Оболочечная арифметика в Справочном руководстве Bash для всех подробностей.
Тодд А. Джейкобс

1
Это не имеет ничего общего с разыменованием, но интерполяцией и exprне приветствуется в 2013 году.
Gilles Quenot

@sputnick Вы явно запутались. Пожалуйста, не стесняйтесь обращаться к словарю. Смотрите разыменование и интерполируйте .
Тодд А. Джейкобс

1
Лучшее слово расширяется , но не разыменование . Разыменование используется, когда мы используем указатели , здесь это не так, это просто простые переменные.
Жиль Квено

1
@Prashant: tldp, как известно, не является хорошей ссылкой в ​​мире bash.
Жиль Квено

1

давайте предположим

x=50
y=5

затем

z=$((x/y))

это будет работать правильно. Но если вы хотите использовать / оператор в операторах case, то он не может решить это. введите код сюда В этом случае используйте простые строки, такие как div или devide или что-то еще. См код


Это не верно. /отлично работает как метка оболочки Что не работает - это использовать *для умножения без цитирования, что может быть тем, что вы на самом деле сделали; это приводит к тому, что он эффективно переопределяет все последующие элементы в кейсе, который в вашем примере является «devide» и «modulo»
dave_thompson_085

0

Чтобы получить числа после десятичной точки, вы можете сделать это: -

read num1 num2
div=`echo $num1 / $num2 |bc -l`
echo $div
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.