Różnica między let, expr i $ []

23

Chcę wiedzieć, jaka dokładnie jest różnica między

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

Wszystkie 4 przypisują zmienną a 2, ale jaka jest różnica?

Z tego, co do tej pory dowiedziałem się, jest to, że wyrażenie jest wolniejsze, ponieważ nie jest to wbudowana powłoka. Ale nic więcej.

ADDB
źródło

Odpowiedzi:

25

Wszystkie dotyczą arytmetyki, ale na różne sposoby, a zmienna jest tworzona na różne sposoby. Niektóre z nich są specyficzne dla bashmuszli, podczas gdy inne nie.

  • $((...))nazywa się rozszerzeniem arytmetycznym , które jest typowe dla powłok bashi ksh. Pozwala to na wykonywanie prostej arytmetyki liczb całkowitych , bez żadnych liczb zmiennoprzecinkowych. Wynik wyrażenia zastępuje wyrażenie, tak jak echo $((1+1))stałoby sięecho 2
  • ((...))jest określany jako ocena arytmetyczna i może być używany jako część instrukcji if ((...)); thenlub while ((...)) ; do. Rozwinięcie interpretacji arytmetycznej $((..))zastępuje wynik operacji i może być użyte do przypisania zmiennych jak w, i=$((i+1))ale nie może być użyte w instrukcjach warunkowych.
  • $[...] to stara składnia interpretacji arytmetycznej, która jest przestarzała. Zobacz także . Zostało to prawdopodobnie zachowane, aby stare bashskrypty nie uległy awarii. To nie działało ksh93, więc przypuszczam, że ta składnia jest specyficzna dla bash. UWAGA : spacje są tutaj bardzo ważne; nie mylić $[1+1]z takimi rzeczami jak [ $a -eq $b ]. Opcja [ze spacjami jest znana jako testpolecenie i zwykle można ją zobaczyć w częściach do podejmowania decyzji. To jest bardzo różne w zachowaniu i celu.
  • letjest słowem kluczowym bashi, kshktóre umożliwia tworzenie zmiennych za pomocą prostej oceny arytmetycznej. Jeśli spróbujesz przypisać ciąg znaków, na przykład let a="hello world"pojawi się błąd składniowy. Działa w bashi ksh93.
  • $(...)to podstawienie polecenia, w którym dosłownie bierzesz wynik polecenia i przypisujesz do zmiennej. Twoje polecenie tutaj expr, które przyjmuje argumenty pozycyjne, tak expr arg1 arg2 arg3więc spacje są ważne. Jest to coś w rodzaju małego kalkulatora wiersza poleceń dla arytmetyki liczb całkowitych oraz niektórych rzeczy typu prawda / fałsz i wyrażenie regularne. Jest to polecenie neutralne dla powłoki.

Warto również zauważyć, że wyrażeń arytmetycznych i podstawianie wyników poleceń są określone przez standard POSIX , natomiast leti $[...]nie są.

Sergiy Kolodyazhnyy
źródło
1
((...))rzeczywiście może być stosowany do zadań w bash, kshi zsh: n=10; ((n+=10)); echo $ndrukuje 20 i ((x=1)); echo $xwydruki 1.
Alexej Magura
1
@Aleksej Dziękuję. Odpowiedź zaktualizowana, ta część została usunięta
Sergiy Kolodyazhnyy
11
  • letKomenda wykonuje arytmetyczna oceny i jest wbudowanym poleceniem powłoki.

    • Uruchom to polecenie i nic nie otrzymasz (tylko ocenia):

      let 1+2
  • $(( ))służy do rozszerzenia arytmetycznego : przeczytaj tutaj

    • Uruchom ten, a pojawi się błąd (z powodu rozszerzenia):

      $((1+2))
  • $[ ] to stara składnia rozszerzania arytmetycznego:

    Stary format $ [wyrażenie] jest przestarzały i zostanie usunięty w nadchodzącym bashu. Strona Bash Man

  • expr jest poleceniem binarnym, jeśli chcesz wykonać rozszerzanie arytmetyczne w ramach podstawienia polecenia, możesz go użyć:

    echo $(expr 1 + 2) 
    echo `expr 1 + 2`
Ravexina
źródło
4

Ponieważ niektóre z powyższych odpowiedzi wyraźnie wspominają ksh93, warto zauważyć, że potrafi wykonywać matematykę zmiennoprzecinkową, np .:

$ print $((1.0/3)) 
0.333333333333333333

Możesz kontrolować precyzję wydruku za pomocą printf, np .:

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

Co najmniej jeden argument musi być podany jako liczba zmiennoprzecinkowa, jak powyżej. Jeśli oba są określone jako liczby całkowite, wówczas wykonywana jest tylko matematyka liczb całkowitych, np .:

$ print $((1/3))  
0

Może to być pomocne, gdy potrzebujesz matematyki zmiennoprzecinkowej w skrypcie powłoki, ponieważ można uniknąć wywoływania polecenia zewnętrznego.

kichać
źródło
Przychodzi mi do głowy, że możesz być zainteresowany opublikowaniem odpowiedzi Czy mogę używać ułamków zwykłych / dziesiętnych w skrypcie bash? Mimo tytułu, myślę, że z kontekstu jasno wynika, że inne pociski w stylu Bourne'a są istotne, dlatego napisałem o zshodpowiedź . Ponieważ kshi bashsą bardziej do siebie podobne (ogólnie) niż którekolwiek z nich zsh, wydaje mi się, że kh93odpowiedź na to pytanie może być bardzo przydatna.
Eliah Kagan,
1

letnie działa w cron. Myślę, że wynika to z letposiadania własnego środowiska. Użyj, $((...))ponieważ jest to POSIX. Na przykład,

let x=1+2
echo x=$x

w cron powoduje „x =”, ale „x = 3” przy uruchomieniu z powłoki.

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

powoduje „x = 3” we wszystkich przypadkach.

SparkEV
źródło