Вы можете сравнить только два числа 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значение, либо входные данные, в зависимости от того, что меньше из wo:
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 массивов, и каждый элемент массива имеет свой собственный стек. Я не использую большую часть этого здесь. Я просто храню строки, как уже упоминалось, так что я могу load их при желании и еx вывести их условно, и я sпорвал $maxзначение в верхней части mмассива.
В любом случае, эта небольшая часть dcделает, в основном, то, что делает ваш shell-скрипт. Он использует GNU-изм-e опцию - как dcправило, берет свои параметры из стандарта - но вы можете сделать то же самое, например:
echo "$script" | cat - /dev/tty | dc
... если бы $scriptвыглядело, как указано выше.
Это работает как:
lTx- Это lвыдает и xизвлекает макрос, хранящийся в верхней части T (для теста, я думаю, я обычно выбираю эти имена произвольно) .
z 0=?- TЭст затем проверяет глубину стека ш / zи, если стек пуст (читай: содержит 0 объектов) он вызывает ?макрос.
? z0!=T q- ?Макрос назван по имени ? dcвстроенной команды, которая читает строку ввода из stdin, но я также добавил еще один zтест глубины стека, чтобы он мог qиспользовать всю маленькую программу, если он вытянет пустую строку или нажмет EOF. Но если это !не так и вместо этого успешно заполняет стек, он вызывает Test снова.
d lm<M- TЗатем est dобновит верхнюю часть стека и сравнит его с $max (как хранится в m) . Если mэто меньшее значение, dcвызывает Mмакрос.
s0 lm- Mпросто выбрасывает верх стека и сбрасывает его в фиктивный скаляр 0- просто дешевый способ вытолкнуть стек. Это также loads mснова, прежде чем вернуться кT EST.
p- Это означает, что если mон меньше текущей вершины стека, то mзаменяет его (в dлюбом случае его дубликат) и находится здесьp печатается, в противном случае это не так, и независимо от того, какой ввод был pвведен, вместо этого печатается.
s0- После этого (потому pчто стек не выталкивается) мы сбрасываем верхнюю часть стека в0 снова , а затем ...
lTx- рекурсивно lполучается Tеще разx ecute его снова.
Таким образом, вы можете запустить этот небольшой отрывок и в интерактивном режиме набрать цифры на своем терминале и 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.