Можна порівняти лише два числа з dcтакими:
dc -e "[$1]sM $2d $1<Mp"
... де "$1"ваше максимальне значення та "$2"число, яке ви б надрукували, якщо воно менше "$1". Для цього також потрібен GNU dc- але ви можете робити те саме, що портативно, як:
dc <<MAX
[$1]sM $2d $1<Mp
MAX
В обох вищезгаданих випадках ви можете встановити точність, відмінне від 0 (за замовчуванням) , як ${desired_precision}k. Для обох також важливо переконатися, що обидва значення безумовно номери, тому що dcможуть system()телефонувати з !оператором.
За допомогою наступного маленького сценарію (і наступного) ви також повинні перевірити вхід, як-то grep -v \!|dcабо щось, щоб надійно обробити довільний ввід. Ви також повинні знати, що dcінтерпретує від'ємні числа з _префіксом, а не -префіксом - тому що останній є оператором віднімання.
Крім цього, за допомогою цього скрипту dcбуде прочитано стільки послідовних \nномерів, що відокремлюються електронною лінією, скільки ви б хотіли його надати, і надрукуйте для кожного $maxзначення або вхід, залежно від того, що менше:
dc -e "${max}sm
[ z 0=? d lm<M p s0 lTx ]ST
[ ? z 0!=T q ]S?
[ s0 lm ]SM lTx"
Так ... кожен з цих [квадратних дужках ]пристроїв є dc рядок об'єкт, Saved кожного до відповідного масиву - будь-який один з T, ?або M. Окрім кількох інших речей, які dcможуть бути виконані зі струною , вона також може виконувати її xяк макрос. Якщо ви правильно це влаштуєте, повністю функціонуючий маленький dcсценарій збирається досить просто.
dcпрацює на стек . Усі вхідні об'єкти укладаються кожен на останній - кожен новий вхідний об'єкт виштовхує останній верхній об'єкт і всі об'єкти під ним вниз на стеку по одному, як він додається. Більшість посилань на об'єкт є до верхнього значення стека, і більшість посилань поп , що вершини стека (який тягне всі об'єкти під ним до одного) .
Крім основного стека, є також (щонайменше) 256 масивів, і кожен елемент масиву має стек все своє. Я не використовую багато цього тут. Я просто зберігаю рядки, як згадувалося, щоб я міг lїх завищувати, коли хотів, і виконувати xїх умовно, і я sзірвав $maxзначення у верхній частині mмасиву.
У будь-якому разі, ця дрібниця dcробить багато в чому те, що робить ваш оболонка-скрипт. Він використовує параметр GNU-ism -e- як dcправило, приймає його параметри від стандартного входу - але ви можете зробити те саме, що:
echo "$script" | cat - /dev/tty | dc
... якщо це $scriptбуло схоже на вищезазначений шматочок.
Це працює так:
lTx- Це нерозумно lта електронно xвиконує макрос, що зберігається у верхній частині T (для тесту, я думаю, я зазвичай вибираю ці назви довільно) .
z 0=?- Test тоді тестує глибину стека w /, zі якщо стек порожній (read: вміщує 0 об'єктів), він викликає ?макрос.
? z0!=T q- ?Макрос названий ? dcвбудованою командою, яка зчитує рядок введення з stdin, але я також додав ще один zтест на глибину стека, щоб він міг qкористуватися цілою маленькою програмою, якщо вона потягне в порожній рядок або натисне EOF. Але якщо цього не відбувається !і натомість успішно заповнює стек, він Tзнову викликає est.
d lm<M- Test потім dускладнить верхню частину стека та порівняє її $max (як це зберігається m) . Якщо mце менше значення, dcвикликає Mмакрос.
s0 lm- Mпросто спливає верхівку стека і скидає його на манекен скаляра 0- просто дешевий спосіб вискочити стек. Крім того, він знову lопускається, mперш ніж повернутися в Test.
p- Це означає, що якщо mменше, ніж поточна вершина стека, то mзамінює його ( dкопія його, все одно), і тут pпоширюється, інакше - ні, і все, що було введено pзамість цього.
s0- Потім (оскільки pне з'являється стек) ми знову скидаємо верхню частину стека 0, а потім ...
lTx- рекурсивно lоад Tще раз, а потім виконувати xце знову.
Таким чином, ви можете запустити цей маленький фрагмент та інтерактивно вводити номери на своєму терміналі та dcнадрукувати вам або число, яке ви ввели, або значення, $maxякщо число, яке ви ввели, було більшим. Він також приймає будь-який файл (наприклад, трубу) як стандартний вхід. Він продовжуватиме цикл читання / порівняння / друку, поки не зустріне порожній рядок або EOF.
Деякі зауваження з цього приводу - я написав це просто для імітації поведінки у вашій функції оболонки, тому вона лише надійно обробляє одне число на рядок. dcоднак можна обробити стільки пробільних цифр на рядок, скільки ви б хотіли кинути на нього. Однак через його стек останній номер у рядку накручується як перший, над яким він працює, і так, як написано, dcдрукував би його результат у зворотному порядку, якщо ви надрукували / набрали більше одного числа на рядок у ньому. Правильний спосіб обробляти, тобто зберігати рядок у масиві, а потім працювати.
Подобається це:
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"
Але ... я не знаю, чи хочу це пояснити настільки ж глибоко. Досить сказати, що, як dcчитається в кожному значенні на стеку, він зберігає або його значення, або $maxзначення в індексованому масиві, і, коли він виявляє стек знову порожній, він друкує кожен індексований об'єкт, перш ніж намагатися прочитати інший рядок введення.
І так, поки перший сценарій робить ...
10 15 20 25 30 ##my input line
20
20
20
15
10 ##see what I mean?
Другий:
10 15 20 25 30 ##my input line
10 ##that's better
15
20
20 ##$max is 20 for both examples
20
Ви можете обробляти поплавці довільної точності, якщо спочатку встановите його kкомандою. І ви можете змінювати iрадіуси nput або output самостійно - що іноді може бути корисним з причин, яких ви можете не очікувати. Наприклад:
echo 100000o 10p|dc
00010
... який спочатку встановлює dcвихідний радіус до 100000, потім друкує 10.