Строка аргумента к целому в bash

74

Попытка выяснить, как преобразовать аргумент в целое число для выполнения арифметики, а затем распечатать его, скажем, для addOne.sh:

echo $1 + 1
>>sh addOne.sh 1
prints 1 + 1
user135986
источник
Я пытаюсь отформатировать ваш вопрос, но он остается каким-то неясным. printf "1 + %s\n" $1 won't do ?
Архемар

Ответы:

89

В bash нельзя «преобразовать аргумент в целое число для выполнения арифметики». В bash переменные обрабатываются как целое число или строка в зависимости от контекста.

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

$ a=2
$ echo "$a + 1"
2 + 1
$ echo "$(($a + 1))"
3

или вообще предпочтительнее:

$ echo "$((a + 1))"
3

Вы должны знать, что bash (в отличие от ksh93, zsh или yash) выполняет только целочисленную арифметику. Если у вас есть числа с плавающей запятой (числа с десятичными числами), то есть другие инструменты, которые могут вам помочь. Например, используйте bc:

$ b=3.14
$ echo "$(($b + 1))"
bash: 3.14 + 1: syntax error: invalid arithmetic operator (error token is ".14 + 1")
$ echo "$b + 1" | bc -l
4.14

Или вы можете использовать оболочку с арифметической поддержкой с плавающей запятой вместо bash:

zsh> echo $((3.14 + 1))
4.14
John1024
источник
Использование $ (()) или (()) небезопасно, если вы не знаете, что это за строки (например, пользовательский ввод). Учтите это: foo = foo ((foo + = 0)) Это приведет к сбою скрипта при попытке рекурсивной оценки foo. То же самое с: foo = foo foo = $ ((foo + 0))
art
12

Другой способ, вы можете использовать expr

Пример:

$ version="0002"
$ expr $version + 0
2
$ expr $version + 1
3
Nam
источник
10

В bash, вы можете выполнить преобразование из целого числа, используя printf -v :

printf -v int '%d\n' "$1" 2>/dev/null

Плавающее число будет преобразовано в целое число, в то время как все, что не похоже на число, будет преобразовано в 0. Возведение в степень будет усечено до числа до e

Пример:

$ printf -v int '%d\n' 123.123 2>/dev/null
$ printf '%d\n' "$int"
123
$ printf -v int '%d\n' abc 2>/dev/null
$ printf '%d\n' "$int"
0
$ printf -v int '%d\n' 1e10 2>/dev/null
$ printf '%d\n' "$int"
1
cuonglm
источник
2
В других оболочках без printf -vэтого можно добиться с помощью подстановки команд:int="$(printf '%d' 123.123 2>/dev/null)"
Адриан Гюнтер
2
Это не работает в Bash.
Майкл Мартинес
@MichaelMartinez ты уверен? Какую версию bashвы использовали?
Cuonglm
GNU bash, версия 4.2.46 (1) -релиз (x86_64-redhat-linux-gnu)
Майкл Мартинес
5

Подобная ситуация возникла недавно при разработке сценариев bash для работы в среде Linux и OSX. Результат одной команды в OSX вернул строку, содержащую код результата; то есть " 0". Конечно, это не удалось проверить правильно в следующем случае:

if [[ $targetCnt != 0 ]]; then...

Решение состояло в том, чтобы принудительно (то есть, «преобразовать») результат в целое число, аналогично тому, что @ John1024 ответил выше, чтобы он работал как ожидалось:

targetCnt=$(($targetCnt + 0))
if [[ $targetCnt != 0 ]]; then...
JESii
источник
3
==и т. д. [[(также [известный как test) сделать сравнение строк. Существуют разные операторы для арифметического сравнения, например [[ $targetcnt -ne 0 ]]; см. man-страницу (или информацию) под условными выражениями. Для того, чтобы обрезать пробелы, вы можете использовать [расширение без [ $targetcnt == 0 ]кавычек, чтобы получить разделение слов по умолчанию (НЕ сделано в [[), но в целом такой подход приводит вас к опасности.
dave_thompson_085
-2

заботьтесь о цветовых кодах, даже в trace ( -x) они не появятся, что выдаст его, так это то, что строка, которая должна быть числом, заключена в кавычки независимо от того, как вы ее печатаете.

untore
источник
1
Отклонено, так как я нахожу ваш ответ немного неясным. Возможно, вы могли бы добавить, что скрипт должен быть исправлен?
Time4Tea
это был лучший ответ при поиске bash + integer + string, поэтому я добавил связанную с ним информацию, которая не была включена в ответы, то есть, когда строки заключены в коды цветов, может быть неясно, почему такие операции, как $((var+var))fail, даже хотя если вы echoили printfоба варя они одинаковы. Я не знаю, как исправить это, поскольку я смог исправить это только путем отключения цветовых кодов в источнике вывода. Чтобы обнаружить его в журналах трассировки, вы увидите, что переменная, для которой var='0'var=0
возникла ошибка,
Что вы можете сделать, так это убедиться, что на выходе нет цветовых кодов, sedесли вы не можете его отключить
отмените