Можна порівняти лише два числа з 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
рядок об'єкт, S
aved кожного до відповідного масиву - будь-який один з 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=?
- T
est тоді тестує глибину стека w /, z
і якщо стек порожній (read: вміщує 0 об'єктів), він викликає ?
макрос.
? z0!=T q
- ?
Макрос названий ?
dc
вбудованою командою, яка зчитує рядок введення з stdin, але я також додав ще один z
тест на глибину стека, щоб він міг q
користуватися цілою маленькою програмою, якщо вона потягне в порожній рядок або натисне EOF. Але якщо цього не відбувається !
і натомість успішно заповнює стек, він T
знову викликає est.
d lm<M
- T
est потім d
ускладнить верхню частину стека та порівняє її $max
(як це зберігається m
) . Якщо m
це менше значення, dc
викликає M
макрос.
s0 lm
- M
просто спливає верхівку стека і скидає його на манекен скаляра 0
- просто дешевий спосіб вискочити стек. Крім того, він знову l
опускається, m
перш ніж повернутися в T
est.
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 або o
utput самостійно - що іноді може бути корисним з причин, яких ви можете не очікувати. Наприклад:
echo 100000o 10p|dc
00010
... який спочатку встановлює dc
вихідний радіус до 100000, потім друкує 10.