Різниця між let, expr та $ []


23

Я хочу знати, в чому саме полягає різниця між

a=$[1+1]
a=$((1+1))
let a=1+1
a=$(expr 1 + 1 )

Усі 4 присвоюють змінну a з 2, але в чому різниця?

З того, що я дізнався поки що, це те, що expr повільніше, оскільки це не фактична вбудована оболонка. Але не більше того.

Відповіді:


25

Усі вони мають справу з арифметикою, але по-різному і змінна створюється різними засобами. Деякі з них характерні для bashоболонок, інші - ні.

  • $((...))називається арифметичним розширенням , характерним для оболонок bashі ksh. Це дозволяє робити просту арифметику з цілим числом , але жодного матеріалу з плаваючою точкою немає. Результат виразу замінює вираз, як echo $((1+1))би ставecho 2
  • ((...))позначається як арифметична оцінка і може використовуватися як частина if ((...)); thenабо while ((...)) ; doтвердження. Арифметичне розширення розширення $((..))замінює результат операції і може використовуватися для призначення змінних як у, i=$((i+1))але не може бути використане в умовних операторах.
  • $[...] - це старий синтаксис арифметичного розширення, який застарілий. Дивіться також . Це, ймовірно, зберігається, щоб старі bashсценарії не зламалися. Це не спрацювало ksh93, тому я гадаю, що цей синтаксис є специфічним для bash. ПРИМІТКА : місця тут дуже важливі; не плутайте $[1+1]подібні речі [ $a -eq $b ]. [З пробілами відомий як testкоманда, і ви зазвичай бачите його в частині прийняття рішень. Це дуже відрізняється за поведінкою та метою.
  • letце bashі kshключове слово , яке дозволяє змінному зі створенням простою арифметичною оцінкою. Якщо ви спробуєте призначити рядок, ніби let a="hello world"ви отримаєте синтаксичну помилку. Працює в bashі ksh93.
  • $(...)це підміна команд, де ви буквально приймаєте висновок команди і призначаєте змінну. Ваша команда тут expr, яка займає позиційні аргументи, як-от expr arg1 arg2 arg3, тому пробіли важливі. Це щось на зразок невеликого калькулятора командного рядка для цілої арифметики, а також деяких істинних / хибних і регулярних виразів. Це команда-нейтральна оболонка.

Варто також відзначити , що арифметика розширення і заміна команди визначаються стандартом POSIX , в той час як letі $[...]немає.


1
((...))насправді можна використовувати для виконання завдань у bash, kshа також zsh: n=10; ((n+=10)); echo $nдрукує 20 та ((x=1)); echo $xдрукує 1.
Олексій Магура

1
@ Алекс Дякую Відповідь оновлена, та частина видалена
Сергій Колодяжний

11
  • letКоманда виконує арифметичну оцінку і є вбудованою оболонкою.

    • Запустіть цю команду, і ви нічого не отримаєте (тільки оцінює):

      let 1+2
  • $(( ))використовується для виконання арифметичного розширення : читайте тут

    • Запустіть цю, і ви отримаєте помилку (через розширення):

      $((1+2))
  • $[ ] - це старий синтаксис для арифметичного розширення:

    Старий формат $ [вираз] застарілий і буде видалений у майбутньому bash. Сторінка чоловіка Баша

  • expr є двійковою командою, якщо ви хочете виконати арифметичне розширення в підстановці команди, ви можете використовувати її:

    echo $(expr 1 + 2) 
    echo `expr 1 + 2`

4

Оскільки деякі відповіді вище конкретно згадують ksh93, варто зазначити, що він може робити математику з плаваючою комою, наприклад:

$ print $((1.0/3)) 
0.333333333333333333

Ви можете контролювати точність виводу за допомогою printf, наприклад:

$ printf "%.4f\n" $((1.0/3))
0.3333

Принаймні один аргумент повинен бути вказаний як число з плаваючою комою, як зазначено вище. Якщо обидва вказані як цілі числа, тоді виконується лише ціла математика, наприклад:

$ print $((1/3))  
0

Це може бути корисно, коли вам потрібна математика з плаваючою комою в сценарії оболонки, оскільки ви можете уникнути виклику зовнішньої команди.


Мені здається, що вам може бути цікаво розмістити відповідь на те, чи можу я використовувати дроби / десяткові знаки в скрипті bash? Незважаючи на назву, я думаю , що контекст ясно , що інші оболонки Bourne стилю актуальні, тому я відправив в zshвідповідь . Оскільки kshі bashсхожі між собою (загалом), ніж будь-який zsh, мені здається, що kh93відповідь на це питання може бути досить корисною.
Елія Каган

1

letне працює в cron. Я думаю, це пов’язано з тим, letщо є власне оточення. Використовуйте, $((...))оскільки це POSIX. Наприклад,

let x=1+2
echo x=$x

в cron, приводить до "x =", але "x = 3" при запуску з оболонки.

x=$((1+2))
echo x=$x

приводить до "x = 3" у всіх випадках.

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