Możesz porównać tylko dwie liczby z dcpodobnymi:
dc -e "[$1]sM $2d $1<Mp"
... gdzie "$1"jest twoja maksymalna wartość i "$2"liczba, którą wydrukowałbyś, gdyby była mniejsza niż "$1". To także wymaga GNU dc- ale możesz zrobić to samo, przenośnie:
dc <<MAX
[$1]sM $2d $1<Mp
MAX
W obu powyższych przypadkach możesz ustawić dokładność na wartość inną niż 0 (domyślnie), np ${desired_precision}k. W obu przypadkach konieczne jest również sprawdzenie, czy obie wartości są zdecydowanie liczbami, ponieważ dcmogą nawiązywać system()połączenia z !operatorem.
Za pomocą następującego małego skryptu (i następnego) powinieneś również zweryfikować dane wejściowe - grep -v \!|dclub coś w celu solidnej obsługi dowolnych danych wejściowych. Powinieneś także wiedzieć, że dcinterpretuje liczby ujemne z _przedrostkiem, a nie -przedrostkiem - ponieważ ten ostatni jest operatorem odejmowania.
Poza tym, ten skrypt dcodczyta tyle kolejnych \nliczb oddzielonych ewline, ile chciałbyś go podać, i wydrukuje dla każdej $maxwartości lub danych wejściowych, w zależności od tego, która z nich jest mniejsza:
dc -e "${max}sm
[ z 0=? d lm<M p s0 lTx ]ST
[ ? z 0!=T q ]S?
[ s0 lm ]SM lTx"
Więc ... każda z tych [kwadratowych nawiasach ]połacie jest dc ciąg obiekt, który jest Saved każdy z odpowiedniej tablicy - każdy jeden T, ?albo M. Poza kilkoma innymi rzeczami, które dcmogą mieć związek z łańcuchem , może również xdziałać jako makro. Jeśli dobrze to uporządkujesz, w pełni funkcjonalny mały dcskrypt jest składany w prosty sposób.
dcdziała na stosie . Wszystkie obiekty wejściowe są układane jeden na drugim - każdy nowy obiekt wejściowy popycha ostatni górny obiekt i wszystkie obiekty poniżej niego na stosie o jeden podczas dodawania. Większość odwołań do obiektu odnosi się do górnej wartości stosu, a większość odnośników wyskakuje na górze stosu (co powoduje pociągnięcie wszystkich obiektów pod nim o jeden) .
Oprócz głównego stosu istnieje również (co najmniej) 256 tablic, a każdy element tablicy ma własny stos. Nie używam dużo tego tutaj. Po prostu przechowuję ciągi, jak wspomniano, więc mogę lje xprzesadzić, kiedy chcę i warunkowo je wyrównać, i spodarłem $maxwartość w górnej części mtablicy.
W każdym razie ta niewielka część dcrobi w dużej mierze to, co robi twój skrypt powłoki. Używa opcji GNU-ism -e- jak dczwykle bierze swoje parametry ze standardowego wejścia - ale możesz zrobić to samo:
echo "$script" | cat - /dev/tty | dc
... gdyby $scriptwyglądało jak wyżej.
Działa jak:
lTx- To lprzysiada i xwylicza makro zapisane na górze T (chyba do testu - zwykle wybieram te nazwy arbitralnie) .
z 0=?- Test następnie sprawdza głębokość stosu w /, za jeśli stos jest pusty (odczyt: zawiera 0 obiektów) , wywołuje ?makro.
? z0!=T q- ?Makro jest nazwane dla ? dcwbudowanego polecenia, które odczytuje wiersz wejścia ze standardowego wejścia, ale dodałem zdo niego również kolejny test głębokości stosu, aby mógł korzystać qz całego małego programu, jeśli wciągnie pusty wiersz lub uderzy w EOF. Ale jeśli !nie, i zamiast tego pomyślnie zapełni stos, wywołuje Tponownie est.
d lm<M- Test następnie dzastosuje górę stosu i porówna go $max (tak jak w pamięci m) . Jeśli mjest to mniejsza wartość, dcwywołuje Mmakro.
s0 lm- Mpo prostu wyskakuje z góry stosu i zrzuca go do manekina skalarnego 0- po prostu tani sposób na zerwanie stosu. To także ponownie lowija msię przed powrotem do Test.
p- Oznacza to, że jeśli mjest mniejszy niż aktualny wierzchołek stosu, to mzastępuje go (w dkażdym razie jego egzemplarz) i jest tutaj ppodszyty, w przeciwnym razie nie zostanie podany, a wszystko, co zostało wprowadzone, jest ppodszyte.
s0- Następnie (ponieważ pnie wyskakuje stos) ponownie wrzucamy górę stosu 0, a następnie ...
lTx- rekurencyjnie load Test jeszcze raz, a potem xponownie.
Abyś mógł uruchomić ten mały fragment kodu i interaktywnie wpisywać liczby w swoim terminalu i dcwydrukować ci albo wpisany numer, albo wartość, $maxjeśli wpisany numer był większy. Akceptuje również dowolny plik (taki jak potok) jako standardowe wejście. Będzie kontynuował pętlę odczytu / porównania / drukowania, aż napotka pustą linię lub EOF.
Kilka uwag na ten temat - napisałem to tylko w celu naśladowania zachowania w twojej funkcji powłoki, więc solidnie obsługuje tylko jedną liczbę w wierszu. dcmoże jednak obsłużyć tyle liczb oddzielonych spacjami w wierszu, ile chcesz w to rzucić. Jednak ze względu na stos, ostatnia liczba w linii kończy się jako pierwsza, na której działa, i tak, jak napisano, dcwydrukowałby swoje wyniki w odwrotnej kolejności, jeśli wydrukowałbyś / wpisała więcej niż jedną liczbę w linii. obsłużyć to, aby zapisać linię w tablicy, a następnie ją przetworzyć.
Lubię to:
dc -e "${max}sm
[ d lm<M la 1+ d sa :a z0!=A ]SA
[ la d ;ap s0 1- d sa 0!=P ]SP
[ ? z 0=q lAx lPx l?x ]S?
[q]Sq [ s0 lm ]SM 0sa l?x"
Ale ... nie wiem, czy chcę to wyjaśnić tak samo głęboko. Wystarczy powiedzieć, że podczas dcodczytu każdej wartości na stosie przechowuje albo swoją wartość, albo $maxwartość w indeksowanej tablicy, a gdy wykryje, że stos jest ponownie pusty, drukuje każdy indeksowany obiekt przed próbą odczytania innego linia wprowadzania.
I tak, podczas gdy pierwszy skrypt robi ...
10 15 20 25 30 ##my input line
20
20
20
15
10 ##see what I mean?
Drugi robi:
10 15 20 25 30 ##my input line
10 ##that's better
15
20
20 ##$max is 20 for both examples
20
Możesz obsługiwać zmiennoprzecinkowe o dowolnej dokładności, jeśli ustawisz je najpierw za pomocą kpolecenia. I możesz niezależnie zmieniać iradia nput lub output - co czasami może być przydatne z powodów, których możesz się nie spodziewać. Na przykład:
echo 100000o 10p|dc
00010
... która najpierw ustawia podstawową dcwartość wyjściową na 100000, a następnie drukuje 10.