Skocz do zawartości
Cyan

[bash] problem z if-em i postacią wykładniczą liczb

Rekomendowane odpowiedzi

Dano nam (ludziom nieświadomym niczego, co jest bashem) do napisania z pozoru prosty skrypt w bashu, który jednak zareagować ma na wszystkie formy liczb, jakie użytkownik może wpisać jako argument. I tak ma wykrywać liczby takie jak: 1, 1.0, .1, 2E-2, +2, 2e+2 i tak dalej. Na samym początku skrypt ma sprawdzić, czy aby nie wpisaliśmy mu czegoś, czego absolutnie nie obsłuży. Podano nam, że taki if powinien działać:

if ! [ "$1" =~ ^[+-]?[0-9]*(\.?[0-9]+)?([eEdDqQ][-+]?[0-9]+)?$ ]; then
ale zamiast działać, skrypt wywala "line 4: [: =~: binary operator expected". Dlaczego? Innym razem (nie pamiętam już, co i gdzie było zmienione) nie spodobał mu się nawias: (. Co jest nie tak z tym warunkiem?

 

I druga sprawa: jak widać powyżej mamy obsłużyć także taką formę jak 2E2 i inne kombinacje. Rzucono nam ochłap w formie poniższej:

a=$(echo $1 | sed 's/[EeDdQq]/+10^/g; s/+//g')
Czy to ma szansę zrobić to, co powinno, mianowicie zamienić wszelkie e, E, etc. na potęgę liczby 10, a mało tego, jeszcze pomnożyć ją przez liczbę przed tym E stojącą (bo tego najbardziej nie mogę się tu doszukać)? Szczerze przyznam, że tej części nie dane mi było sprawdzić, jako że powyższy warunek ciągle wywalał cały skrypt.

 

W związku z powyższymi bardzo proszę o pomoc.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Gość <account_deleted>

Czy tak trudno przeczytać <niezbyt długą> dokumentację basha i poszukać paru przykładów?

Pierwsza linia to nieporozumienie a komunikat błędu dokładnie wyjaśnia przyczynę.

Druga wersja już trochę lepsza (aczkolwiek niekompletna) natomiast operacje matematyczne jak najbardziej mogą być w takiej sytuacji wykonane - tyle że tu również masz błąd -> zobacz sobie jak wygląda zapis operacji potęgowania w skrypcie. W przypadku ujemnych wykładników nieuniknine stanie się wykorzystanie bc.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Gdyby w dokumentacji udało mi się znaleźć coś, co choćby trochę wyjaśniłoby mi sprawę, to by mnie tu generalnie nie było. Nie wiem, czego szukam, co jest moim głównym problemem, bo podano nam tę linijkę kodu jako działającą na pewno, więc nie rozumiem, czemu nie działa. Komunikat błędu powiedział mi dokładnie tyle, co Google na ten temat - nic, żadnego wyjaśnienia, które by do mnie dotarło.

No i wybacz, ale ja po prostu nie wiem, co jest w tym skrypcie, bo ta linijka jest dla mnie kompletnie niezrozumiała i widzę jedynie, że wypisuje to swoje 10 do potęgi, ale nawet go nie oblicza.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Gość <account_deleted>

No to ja chyba jestem nadnieprzeciętnie uzdolniony, bo po 10s znalazłem że "~" to operator dla bitowej negacji, natomiast potęgę zapisuje się jako "**" a nie "^"

 

rozwiń przykład:

echo $[ $(echo "2e3" | sed 's/e/ \* 10 \*\* /') ]

 

;)

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Ja rozumiem istnienie tej negacji zapisanej tyldą, ale wciąż przecież operator =~ gdzieś istnieje, a przynajmniej powinien, bo inaczej co innego tam wstawić...? Takiej głupoty by nam chyba nie podali...

No nie wiem, dotychczas ^ działało jako potęga, ale aż głupio to mówić, gdy się widzi, że ** działają... Więc mój błąd, dzięki.

Nie zmienia to faktu, że nadal brak mi operatora, który przyrównałby treść parametru do, nie wiem, schematu? Ma to w ogóle jakąś nazwę, bo nawet nie wiem, czego szukać?

 

Aha, właśnie próbowałem =~ na == podmienić, bo w jakiejś innej wersji tegoż przykładu zrobili coś takiego, ale wówczas wielkie oburzenie ze strony programu:

line 4: syntax error near unexpected token `('

Jeszcze jakieś możliwości...?

Edytowane przez Cyan

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Gość <account_deleted>

Nie kapuję jak ci tajemniczy "oni" mogli kazać bliżej nie określonym "wam" wykonać zadanie wymagające podstawowej znajomości regex <regular expressions>, które to nazywasz "schematem" ...

"+" jest znakiem specjalnym w regex i musi być poprzedzony backslashem żeby można go było użyć we wzorcu - nie jest to jedyny błąd niestety. To samo dotyczy "**" ponieważ "^" jest również znakiem specjalnym - nigdy nie było inaczej - rozszerzenia basha powstały później niż POSIX/RegEx.

Poza tym (a w zasadzie na początku) wypadałoby określić wersję basha i pod jakim systemem on działa, bo występują pewne różnice pomiędzy wersjami dla linuxa, unixa i windowsa, są też różne poziomy wsparcia RegEx.

 

edit:

Mała podpowiedź do poprzedniej podpowiedzi: Bash nie posiada w swojej składni operatora "=~", a zauważyłbyś to po przeczytaniu manuala. Jest to operator komendy test, co można wyczytać w każdym niemal opisie operacji na stringach czy po prostu w opisie komendy if. W takim przypadku nawiasy kwadratowe muszą być jednak podwójne [[...]], ponieważ pierwszy zastępuje <oznacza> komędę test (alias), natomiast dopiero drugi obejmuje wyrażenie ( nie trzeba pisać: test[...] ). Poza tym jednak ten pattern regex jest do d. bo nie nadaje się do zadania które dostaliście... (no i ktoś coś popitolił przy spisywaniu)

Edytowane przez tomazzi

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Boże... + w tym wyrażeniu (ponoć) oznacza, że to co jest przed nim ma się pojawić 1 lub więcej razy...

 

Widzę, że to nie ma sensu, ale na forach jeszcze nigdy nic nie uzyskałem, jakimś cudem. I nic nie popitoliłem przy spisywaniu, tylko ćwiczeniowiec podaje nam zadania z błędami, byśmy je sobie znaleźli. Ale jak widzę niemożliwym jest rozwiązanie tego, gdy się nie programuje od kilku lat, bo żadnej konkretnej odpowiedzi od razu dostać nie można. (test z dwoma nawiasami też nie działa w tym przykładzie, swoją drogą.)

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Gość <account_deleted>

Boże... + w tym wyrażeniu (ponoć) oznacza, że to co jest przed nim ma się pojawić 1 lub więcej razy...

 

Widzę, że to nie ma sensu, ale na forach jeszcze nigdy nic nie uzyskałem, jakimś cudem. I nic nie popitoliłem przy spisywaniu, tylko ćwiczeniowiec podaje nam zadania z błędami, byśmy je sobie znaleźli. Ale jak widzę niemożliwym jest rozwiązanie tego, gdy się nie programuje od kilku lat, bo żadnej konkretnej odpowiedzi od razu dostać nie można. (test z dwoma nawiasami też nie działa w tym przykładzie, swoją drogą.)

 

Boże...

 

Tajny kod skryptu:

#!/bin/bashregex="^[+-]?[0-9]*(\.?[0-9]+)?([eEdDqQ][-+]?[0-9]+)?$"if [[ "$1" =~ $regex ]]; then echo $1 ": format ok"else echo "not a number"fiexit 0
...

"+" ponoć to oznacza, ale zależy gdzie jest umieszczony i w jaki sposób. Nie podałeś jaka platforma ani jaka wersja basha - [-+], [+-] oraz [-\+] nie zawsze będą działać tak samo, poza tym brak konsekwencji w tworzeniu patternów - to nie jest VB dla blondynek.

 

To dopiero początek zadania - jazda zaczyna się dalej, ale jak chcesz pomocy to może w końcu coś napisz a nie tylko biadolisz że nigdzie nie ma informacji i jakie te fora są bee...

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Dobra, nie mam pojęcia jaka jest różnica między zapisaniem w tym if-ie samego wyrażenia a zapisaniem go do zmiennej, ale widać tego rozumieć nie muszę, skoro generalnie działa, za co wypada mi już tylko podziękować, bo przynajmniej to żyje. Nie można było tego od razu wyartykułować?

 

Co do platform, to kryterium było zaiste optymistyczne: ma działać wszędzie, a zwłaszcza u ćwiczeniowca (żadnej wytycznej). Wersji basha sprawdzić nie umiem.

 

Ja nic nie piszę? No cóż, nie będę się kłócić, bo nie po o tu siedzimy. A że to dopiero początek to widzę, choć nazwałbym to raczej środkiem, patrząc na to, co już działa. Widzę, że teraz skrypt wywala się przy liczbach z kropką jak 2.2, ale aż boję się zapytać, czemu to robi. Aczkolwiek śmieszy mnie to, bo dopisując kropkę do części podmieniającej literki skrypt robi, co mu się każe:

 

b=$[$(echo $1 | sed 's/[EeDdQq\.]/ \* 10 \*\* /')] (<-chwilowo z tą nieszczęsną dziesiątką)

 

ale gdy próbuję kazać mu podmienić samą kropkę:

 

b=$[$(echo $1 | sed 's/\./ \* 10 \*\* /')]

 

to już mu się nie podoba i omija tę linijkę (albo nie znajduje dla niej zastosowania, nie wiem, w każdym razie w niższej linii się burzy).

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Gość <account_deleted>

Dobra, nie mam pojęcia jaka jest różnica między zapisaniem w tym if-ie samego wyrażenia a zapisaniem go do zmiennej,ale widać tego rozumieć nie muszę, skoro generalnie działa

...

Nie można było tego od razu wyartykułować?

Prawda, wogóle nic nie musisz rozumieć. Jest tutaj przyjęta zasada, że prace domowe odrabiamy samodzielnie, więc źle postąpiłem bo odrobiłem za Ciebie lekcje.

 

Co do platform, to kryterium było zaiste optymistyczne: ma działać wszędzie, a zwłaszcza u ćwiczeniowca (żadnej wytycznej). Wersji basha sprawdzić nie umiem.

Dlatego należy stosować składnię która jest zawsze poprawna, czyli np. escapować znaki specjalne...

Zaawansowana metoda sprawdzania wersji basha: bash --version :lol:

 

Widzę, że teraz skrypt wywala się przy liczbach z kropką jak 2.2, ale aż boję się zapytać, czemu to robi. Aczkolwiek śmieszy mnie to, bo dopisując kropkę do części podmieniającej literki skrypt robi, co mu się każe:

 

b=$[$(echo $1 | sed 's/[EeDdQq\.]/ \* 10 \*\* /')] (<-chwilowo z tą nieszczęsną dziesiątką)

 

ale gdy próbuję kazać mu podmienić samą kropkę:

 

b=$[$(echo $1 | sed 's/\./ \* 10 \*\* /')]

 

to już mu się nie podoba i omija tę linijkę (albo nie znajduje dla niej zastosowania, nie wiem, w każdym razie w niższej linii się burzy).

Główny problem polega na tym że się nie uczysz. Ciekawe, że podobno od lat programujesz a popełniasz tak elementarne błędy logiczne:

"2.1" = 2*10^1 ? -> raczej nie

"2.1e3" -> "2 * 10 ** 1e3" ... co to ma być?

 

Linia z "podmianą kropki" działa -> jaja se robisz? "burzy się" -> to Twoim zdaniem jest sposób na rozwiązanie problemu? Może podasz z łaski swojej treść komunikatu błędu?

 

Podam Ci tylko co trzeba zrobić, nie odrobię za Ciebie lekcji:

1. Trzeba napisać różne wersje warunków dla różnych postaci liczb (kilka przypadków), albo napisać skrypt sed'a -> to co powyżej to 0.1% jego możliwości. Można np. najpierw sprawdzać, czy jest to postać wykładnicza, czy nie.

2. Arytmetyczne rozszerzenia basha nie obsługują typu float -> od tego jest bc. Z tego wynika że program będzie inaczej wyglądał jeśli chcesz użyć wbudowanej arytmetyki basha (są pewne ograniczenia ->3) a inaczej gdy chcesz full opcję z wykorzystaniem bc ->4.

3. Bash obsługuje tylko integer, więc wszystkie liczby muszą się w tym zmieścić oraz wszystkie trzeba przekonwertować do czystego int, czyli ujemne wykładniki i ułamki nie przejdą o ile nie zastosujesz jakiegoś tricku, np. takiego prehistorycznego jak pomnożenie wszystkich ułamków przez 1000. Inna opcja to "składanie" stringów z oddzielnie obliczonej częsci całkowitej i ułamkowej.

4. Polecam bc - jest normalnym kalkulatorem z obsługą skryptów -> można zrobić wszystko, trzeba tylko nieco zmienić zapis postaci wykładniczej liczb. Na pewno będzie łatwiej.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Stwierdziłem, że "nie muszę rozumieć", bo widzę jak rozpala cię chęć wyjaśnienia, a nigdzie indziej tej informacji nie dostanę.

Najłatwiej sobie postawić zachwyconą buźkę. Nie pomyślałeś, że ktoś mógł nigdy nie mieć do czynienia z bashem? Ale pewnie, przecież ekspert już dawno zapomniał jak to było gdy pierwszy raz otworzył konsolę i zastanawiał się, co tu zrobić. Bardzo dojrzale.

I gdzie niby napisałem, że od lat programuje? Boże, naucz się czytać. Stoi jak wół, że nigdy z bashem do czynienia nie miałem, a ty mi wyskakujesz z kilkuletnim doświadczeniem...? No kpisz sobie chyba.

A kropkę wstawiłem w tamten kod, by w ogóle sprawdzić, czy ją na COKOLWIEK zamieni, do głowy by mi nie wpadło, że ktoś uzna, że to miało być rozwiązanie. Trzeba naprawdę być kreatywnym, by coś podobnego wymyślić...

I po co ci komunikat, skoro od razu wiesz, co jest źle?...

 

3. Bash obsługuje tylko integer, więc wszystkie liczby muszą się w tym zmieścić oraz wszystkie trzeba przekonwertować do czystego int, czyli ujemne wykładniki i ułamki nie przejdą o ile nie zastosujesz jakiegoś tricku, np. takiego prehistorycznego jak pomnożenie wszystkich ułamków przez 1000. Inna opcja to "składanie" stringów z oddzielnie obliczonej częsci całkowitej i ułamkowej.

 

Do tego, że bash obsługuje tylko całkowite liczby, to ja za przeproszeniem sam doszedłem i chyba nie dość jasno napisałem, że nie mogę wyłuskać kropki ze stringa, by potem scalić liczbę i podzielić ją przez cokolwiek, czy w ogóle zrobić z nią coś, by zmieniła się w liczbę, którą bash zrozumie. Widać zamiast czytać, wolałeś się wykrzyczeć.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Gość <account_deleted>

Po prostu nie wierzę, że nikt wam wcześniej nie prowadził wykładów lub nie podał źródeł skąd wziąć informacje -> IMO wniosek jest prosty -> olewało się naukę, przyszły ćwiczenia i jest kupa...

Nawet nie zadałeś sobie trudu żeby wyszukać w google jak sprawdzić wersję programu na którym pracujesz - ogólnie to jest śmieszne, ale mnie akurat irytuje.

 

Nie zapomniałem jak zaczynałem naukę basha -> ryłem dokumentację i internet, ani jednego posta nie napisałem bo WSZYSTKO można znaleźć wraz z przykładami, tylko trzeba chcieć.

 

Zasadą w przypadku pojawienia się błędu jest podanie treści komunikatu, bo różne opcje są możliwe -> zdziwiony? Nie jest za to dziwne dla czego narzekasz na fora -> nikt nie toleruje leserów którzy liczą że ktoś za nich odrobi lekcje. A skoro już sam wiesz jaki jest problem to zostało jedynie nauczyć się składni...

 

powodzenia.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

No to uwierz, że nam nie podawali. Udowodnić ci tego nie mogę/nie chce mi się. Tak jest i już, a ja tu nie przyszedłem dyskutować o poziomie edukacyjnym.

Próbowałem znaleźć to w Google, ale gdy na trzeciej stronie wciąż dostaję jakieś totalne głupoty, mam chyba prawo zrezygnować.

Powiem ci to grzecznie i raz: wypchaj się. Nie proszę o napisanie całego programu tylko jednej z kilkunatu funkcji, na której utknąłem. A "nauczyć się składni" to można powiedzieć o języku, o którym cokolwiek piszą. Dziwne, że jakoś nic znaleźć nie mogę i z tego co widzę po osobach z grupy, nie tylko ja mam "taki Google", w którym nic nie można znaleźć, zwłaszcza mając do dyspozycji kilka dni, w które taaak się mogę nauczyć składni, że aż szok.

I takim oto sposobem idea Web 2.0 wzięła w łeb. Dziękuję za wsparcie dla laika.

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Gość <account_deleted>

Powiem ci to grzecznie i raz: wypchaj się.

...

Dziękuję za wsparcie dla laika.

Zgadnij skąd pochodzi ten cytat... (jest identyczny po polsku jeśli masz polską lokalizację systemu):

[[ expression ]] Return a status of 0 or 1 depending on the evaluateuation of the conditional expression expression.

(...)

An additional binary operator "=~" is available, with the same precedence as == and !=. When it is used, the string to the right of the operator is considered an extended regular expression and matched accordingly (as in regex(3)). The return value is 0 if the string matches the pattern, and 1 otherwise. If the regular expression is syntactically incorrect, the conditional expression's return value is 2. If the shell option nocasematch is enabled, the match is performed without regard to the case of alphabetic characters. Any part of the pattern may be quoted to force it to be matched as a string. Substrings matched by parenthesized subexpressions within the regular expression are saved in the array variable BASH_REMATCH. The element of BASH_REMATCH with index 0 is the portion of the string matching the entire regular expression. The element of BASH_REMATCH with index n is the portion of the string matching the nth parenthesized subexpression.

Opis opereacji wykonywanych przy okazji b=$[...] znajduje się pod akapitem "Arithmetic evaluateuation"

 

Sam sobie odpowiedz na pytanie czy jesteś laikiem czy leniwym leserem...

Edytowane przez tomazzi

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Dołącz do dyskusji

Możesz dodać zawartość już teraz a zarejestrować się później. Jeśli posiadasz już konto, zaloguj się aby dodać zawartość za jego pomocą.

Gość
Dodaj odpowiedź do tematu...

×   Wklejono zawartość z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Odnośnik został automatycznie osadzony.   Przywróć wyświetlanie jako odnośnik

×   Przywrócono poprzednią zawartość.   Wyczyść edytor

×   Nie możesz bezpośrednio wkleić grafiki. Dodaj lub załącz grafiki z adresu URL.

Ładowanie


×
×
  • Dodaj nową pozycję...