Używając wyrażenia, $ (()), (())

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

Odpowiedź

  1. W przypadku arytmetyki expr jest archaiczne. Nie używaj go. *

  2. $((...)) i ((...)) są bardzo podobne. Oba obliczają tylko liczby całkowite. Różnica polega na tym, że $((...)) zwraca wynik obliczenia, a ((...)) nie. Zatem $((...)) jest przydatne w echo 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 
  3. Jeśli chcesz, aby zmienna obliczenia punktowe, użyj bc lub awk:

    $ 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ć jako case 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ć jako case 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.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *