Рядок аргументу до цілого числа в bash


73

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

echo $1 + 1
>>sh addOne.sh 1
prints 1 + 1

Я намагаюся відформатувати ваше питання, але це залишається якось незрозумілим. printf "1 + %s\n" $1 won't do ?
Архемар

Відповіді:


87

У 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

Використання $ (()) або (()) небезпечно, якщо ви не знаєте, що таке рядки (наприклад, введення користувача). Врахуйте це: foo = foo ((foo + = 0)) Це призведе до краху сценарію, оскільки він намагається рекурсивно оцінювати foo. Те саме з: foo = foo foo = $ ((foo + 0))
арт

12

Іншим способом можна скористатися expr

Наприклад:

$ version="0002"
$ expr $version + 0
2
$ expr $version + 1
3

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

2
В інших оболонках без printf -vцього можна домогтися заміни команд:int="$(printf '%d' 123.123 2>/dev/null)"
Адріан Гюнтер

2
Це не працює в баш.
Майкл Мартінес

@MichaelMartinez ви впевнені? Яку версію bashви використовували?
cuonglm

GNU bash, версія 4.2.46 (1) -випуск (x86_64-redhat-linux-gnu)
Michael Martinez

5

Аналогічна ситуація виникла нещодавно при розробці bash-скриптів для роботи як в Linux, так і в OSX. Результат однієї команди в OSX повернув рядок, що містить код результату; тобто " 0". Звичайно, це не вдалося перевірити правильно у наступному випадку:

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

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

targetCnt=$(($targetCnt + 0))
if [[ $targetCnt != 0 ]]; then...

3
==і т.д. в [[(також [aka test) робити порівняння рядків. Існують різні оператори для арифметичного порівняння, наприклад [[ $targetcnt -ne 0 ]]; див. сторінку (або інформацію) у розділі Умовні вирази. Щоб спеціально обрізати пробіли, ви можете використовувати [розширення без [ $targetcnt == 0 ]змін, що цитуються, щоб отримати розбивання слів за замовчуванням (НЕ робиться в [[), але загалом такий підхід приводить вас до небезпеки.
dave_thompson_085

-2

дбайте про кольори кольорів, навіть у слідах ( -x) вони не з’являться. Що б це не було, це те, що рядок, який повинен бути числом, загорнутий у лапки незалежно від того, як ви їх друкуєте.


1
Проголосував проти, оскільки я вважаю вашу відповідь трохи незрозумілою. Можливо, ви могли б додати те, до чого слід виправити сценарій?
Time4Tea

це була головна відповідь у пошуку bash + integer + string, тому я додав інформацію, пов’язану з нею, яка не була включена до відповідей, тобто коли рядки загорнуті в кольорові коди, може бути незрозуміло, чому такі операції, як $((var+var))не вдатися навіть хоча якщо ви echoабо printfобидва вари, вони однакові. Я не знаю виправлення, оскільки мені вдалося виправити його лише відключивши кольорові коди у джерелі виводу. Щоб помітити його в журналах слідів, ви побачите змінну, що порушує право, присвоєну так, var='0'як це просто повинно бутиvar=0
untore

Що ви можете зробити, це переконатися, що на виході немає кольорових кодів, sedякщо ви не можете вимкнути його
untore
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.