W skrypcie powłoki możemy zastąpić expr $a*$b
$(($a+$b))
.
Ale dlaczego nie tylko z (($a+$b))
, ponieważ w każdym zasobie jest napisane, że (())
służy do obliczania liczb całkowitych.
Więc używamy $(())
, gdy zamiast liczb całkowitych są zmienne, prawda? A czego powinniśmy używać zamiast $(())
, gdy zmienne mogą przyjmować wartości zmiennoprzecinkowe?
Komentarze
- Zobacz także unix.stackexchange.com/questions/149823/…
Odpowiedź
-
W przypadku arytmetyki
expr
jest archaiczne. Nie używaj go. * -
$((...))
i((...))
są bardzo podobne. Oba obliczają tylko liczby całkowite. Różnica polega na tym, że$((...))
zwraca wynik obliczenia, a((...))
nie. Zatem$((...))
jest przydatne wecho
stwierdzeniach:$ a=2; b=3; echo $((a*b)) 6
((...))
jest przydatne, gdy chcesz przypisać zmienną lub ustawić kod zakończenia:$ a=3; b=3; ((a==b)) && echo yes yes
-
Jeśli chcesz, aby zmienna obliczenia punktowe, użyj
bc
lubawk
:$ echo "4.7/3.14" | bc -l 1.49681528662420382165 $ awk "BEGIN{print 4.7/3.14}" 1.49682
* Na marginesie, expr
pozostaje użyteczne do obsługi ciągów znaków, gdy elementy glob nie są wystarczająco dobre, a do obsługi wyrażeń regularnych potrzebna jest metoda POSIX.
Komentarze
- Jeśli wyrażenie jest archaiczne, czego powinniśmy użyć zamiast tekstu wyrażenia: '. * '
- Jeśli
s
jest zmienną powłoki, jej długość wynosi${#s}
- $ {#} oznacza liczbę argumentów, a $ (# s} oznacza liczbę znaków zmiennej, prawda?
- Tak. To ' ma rację.
- @Stranger Wiele zastosowań
expr STRING : REGEX
można zapisać jakocase STRING in PATTERN)
.expr
jest przydatne tylko wtedy, gdy REGEX nie może ' być wyrażony za pomocą symboli wieloznacznych.
Answer
wyrażenie jest stare, ale ma jedno ograniczone zastosowanie, o którym mogę pomyśleć. Powiedz, że chcesz wyszukać ciąg. Jeśli chcesz pozostać POSIX z grep, musisz użyć potoku:
if echo november | grep nov then : do something fi
wyrażenie może to zrobić bez potoku:
if expr november : nov then : do something fi
jedynym haczykiem jest wyrażenie, które działa z zakotwiczonymi ciągami, więc jeśli chcesz dopasować po początku, musisz zmienić REGEXP:
if expr november : ".*ber" then : do something fi
Jeśli chodzi o (( ))
, ta konstrukcja nie jest zgodna z POSIX , dlatego należy jej unikać.
Jeśli chodzi o $(( ))
, nie musisz dodawać znaku dolara:
$ fo=1 $ go=2 $ echo $((fo + go)) 3
Komentarze
- Wiele zastosowań
expr STRING : REGEX
można zapisać jakocase STRING in PATTERN)
.expr
jest przydatne tylko wtedy, gdy REGEX nie może ' być wyrażony za pomocą symboli wieloznacznych.
Odpowiedź
Wygląda na to, że poniższe programy robią mniej więcej to samo i tak naprawdę się nie różnią. Ale to nieprawda.
#!/bin/bash s=-1000 for (( i=0; i<1000000; i++ )), do s=$((s+1)) echo $s
To jest poprawny sposób implementacji tego. Wyrażenie s + 1 jest oceniane przez powłokę i może być przypisane do zmiennej.
#!/bin/bash s=-1000 for (( i=0; i<1000000; i++ )), do s=`expr $s+1` echo $s
Tutaj wyrażenie zostanie obliczone przez program expr, który nie jest wbudowany w powłokę, ale jest zewnętrznym programem uniksowym. Dlatego zamiast po prostu dodawać 1 i s, program musi zostać uruchomiony, a jego wyjście musi zostać odczytane i zapisane w zmiennej. Uruchomienie programu wymaga wielu zasobów i czasu. Ten program jest uruchamiany 1000000 razy. Tak więc program będzie znacznie wolniejszy niż poprzedni. Niemniej jednak kod działa poprawnie.
#!/bin/bash -e s=-1000 for (( i=0; i<1000000; i++ )), do ((s=s+1)) echo $s
Jeśli flaga -e nie jest ustawiona „t”, program też będzie działał poprawnie. Ale jeśli opcja -e jest ustawiona, gdy s = -1 i ((s = s + 1)) jest obliczane. Wyrażenie s = s + 1 daje 0, a kod zakończenia ((0)) jest> 0, co jest interpretowane przez powłokę jako błąd i powłoka kończy działanie programu.
Powodem ustawienia flagi -e jest to, że jest to najprostszy sposób przetwarzania błędów: zatrzymaj, jeśli wystąpi błąd.