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
exprjest 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 wechostwierdzeniach:$ 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
bclubawk:$ 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
sjest 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 : REGEXmożna zapisać jakocase STRING in PATTERN).exprjest 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 : REGEXmożna zapisać jakocase STRING in PATTERN).exprjest 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.