Вы можете сравнить только два числа 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
строка объект, S
aved каждого к соответствующему массиву - любой один из T
, ?
или M
. Помимо некоторых других вещейdc
могут быть связаны со строкой , она также может быть использована x
как макрос. Если вы все устроите правильно, полноценный маленький dc
скрипт будет собран достаточно просто.
dc
работает в стеке . Все входные объекты накладываются друг на друга последним - каждый новый входной объект помещает последний верхний объект и все объекты под ним в стек по одному при его добавлении. Большинство ссылок на объект являются к верхнему значению стека, и большинство ссылок поп , что вершины стека (который тянет все объекты под ним до одного) .
Помимо основного стека, есть также (как минимум) 256 массивов, и каждый элемент массива имеет свой собственный стек. Я не использую большую часть этого здесь. Я просто храню строки, как уже упоминалось, так что я могу l
oad их при желании и е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. Но если это !
не так и вместо этого успешно заполняет стек, он вызывает T
est снова.
d lm<M
- T
Затем est d
обновит верхнюю часть стека и сравнит его с $max
(как хранится в m
) . Если m
это меньшее значение, dc
вызывает M
макрос.
s0 lm
- M
просто выбрасывает верх стека и сбрасывает его в фиктивный скаляр 0
- просто дешевый способ вытолкнуть стек. Это также l
oads 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 или o
utput независимо друг от друга, что иногда может быть полезно по причинам, которые вы не ожидаете. Например:
echo 100000o 10p|dc
00010
... который сначала устанавливает dc
выходной радиус 100000, а затем печатает 10.
dc
каждый раз, чтобы держать его в напряжении.dc
это переменчивый зверь, но он может быть самой быстрой и самой странно способной общей утилитой в любой системе Unix. Когда в паре ж /sed
она может делать некоторые необычные вещи. Я играл с этим и вdd
последнее время, чтобы я мог заменить это чудовищеreadline
. Вот небольшой пример того, чем я занимался. Делатьrev
вdc
это почти детская игра.[string]P91P93P[string]P
. Так что у меня есть кое-что изsed
вас, которое может оказаться полезным:sed 's/[][]/]P93]&[1P[/g;s/[]3][]][[][1[]//g'
которое всегда должно корректно заменять квадраты скобкой закрытия строки, затем aP
, затем десятичное значение ascii квадрата и другоеP
; затем открытая[
квадратная скобка, чтобы продолжить строку. Не знаю, если вы перепутали w /dc
s возможности преобразования строк / чисел, но - особенно в сочетании с wod
- это может быть довольно забавно.Если вы знаете, что имеете дело с двумя целыми числами
a
иb
, то этих простых арифметических разложений с использованием тернарного оператора достаточно, чтобы получить числовой максимум:и числовой мин:
Например
Вот скрипт оболочки, демонстрирующий это:
источник
max=$(( a >= b ? a : b ))
, но результат полностью одинаков - если a и b равны, то не имеет значения, какой из них возвращается. Это то, что вы спрашиваете?if (( a >= b )); then echo a is greater than or equal to b; fi
- это то, что вы просите? (обратите внимание на использование(( ))
здесь вместо$(( ))
)sort
иhead
может сделать это:источник
O(n log(n))
пока эффективная реализация maxO(n)
. Это наше небольшое значениеn=2
, так как порождение двух процессов намного больше накладных расходов.numbers="1 4 3 5 7 1 10 21 8";
echo $numbers | tr ' ' "\n" | sort -rn | head -n 1
max=0; for x in $numbers ; do test $x -gt $max && max=$x ; done
Вы можете определить библиотеку предопределенных математических функций
bc
и затем использовать их в командной строке.Например, включите в текстовый файл следующее
~/MyExtensions.bc
:Теперь вы можете позвонить
bc
по:К вашему сведению, в интернете есть бесплатные математические функции, такие как эта .
Используя этот файл, вы можете легко вычислить более сложные функции, такие как
GCD
:источник
bc
s до сих пор являются толькоdc
внешними интерфейсами , даже если GNUbc
больше не является таковым (но GNUdc
и GNUbc
имеют колоссальное количество своей кодовой базы) . В любом случае, это может быть лучшим ответом здесь.bc
прямо перед вызовом функции. Тогда второй файл не нужен :)Слишком долго для комментария:
Хотя вы можете делать эти вещи, например, с помощью
sort | head
илиsort | tail
комбинаций, это кажется довольно неоптимальным с точки зрения как ресурсов, так и обработки ошибок. Что касается выполнения, то комбо означает порождение двух процессов только для проверки двух строк. Это кажется излишним.Более серьезная проблема заключается в том, что в большинстве случаев вам нужно знать, что ввод вменяется, то есть содержит только цифры. Решение @ glennjackmann ловко решает эту проблему, так как
printf %d
должно препятствовать нецелым числам. Он также не будет работать с плавающей точкой (если вы не измените спецификатор формата на%f
, где вы столкнетесь с проблемами округления).test $1 -gt $2
даст вам представление о том, было ли сравнение неудачным или нет (выход из состояния 2 означает, что во время теста произошла ошибка. Так как обычно это встроенная оболочка, не возникает никакого дополнительного процесса - мы говорим о порядке сотен В разы быстрее выполнение. Работает только с целыми числами.Если вам нужно сравнить пару чисел с плавающей точкой, интересным вариантом может быть
bc
:будет эквивалентно
test $1 -gt $2
, и использование в в оболочке:все еще почти в 2,5 раза быстрее
printf | sort | head
(для двух чисел).Если вы можете полагаться на расширения GNU в
bc
, то вы также можете использоватьread()
функцию для чтения чисел непосредственно вbc
скрипт.источник
dc -e "${max}sm[z0=?dlm<Mps0lTx]ST[?z0!=Tq]S?[s0lm]SMlTx"
- о, за исключением того, чтоdc
все это делает (исключая эхо, хотя могло бы) - он читает stdin и печатает либо$max
номер ввода, либо в зависимости от того, какой меньше В любом случае, мне все равно, что я хочу объяснить, а твой ответ лучше, чем я собирался написать. Так что, пожалуйста, возьми мой голос.dc
сценарий было бы очень хорошо, RPN не так часто встречается в наши дни.dc
можете выполнить ввод / вывод самостоятельно, это будет даже более элегантно, чем.Чтобы получить большее значение $ a и $ b, используйте это:
Но вам нужно что-то вокруг этого, вы, вероятно, не хотите выполнять число, поэтому для отображения большего значения из двух используйте «echo»
Вышесказанное прекрасно вписывается в функцию оболочки, например
Чтобы назначить большую из двух переменной, используйте эту модифицированную версию:
или используйте определенную функцию:
Изменение функции также дает вам возможность аккуратно добавить проверку ошибок ввода.
Чтобы вернуть максимум двух десятичных чисел / чисел с плавающей запятой, вы можете использовать
awk
РЕДАКТИРОВАТЬ: Используя эту технику, вы можете создать «лимитную» функцию, которая работает наоборот в соответствии с вашими правками / примечаниями. Эта функция вернет нижнюю из двух, например:
Мне нравится помещать служебные функции в отдельный файл, вызывать его
myprogram.funcs
и использовать в сценарии следующим образом:FWIW это все еще делает то, что вы сделали, и ваша версия, даже если она более многословна, так же эффективна.
Более компактная форма на самом деле не лучше, но предотвращает беспорядок в ваших скриптах. Если у вас много простых конструкций if-then-else-fi, скрипт быстро расширяется.
Если вы хотите повторно использовать проверку больших / меньших чисел несколько раз в одном скрипте, поместите ее в функцию. Формат функции облегчает отладку и повторное использование и позволяет легко заменить эту часть сценария, например, командой awk, чтобы иметь возможность обрабатывать нецелые десятичные числа.
Если это единственный вариант использования, просто закодируйте его в строке.
источник
Вы можете определить функцию как
Назовите это как,
maxnum 54 42
и это повторяет54
. Вы можете добавить информацию проверки в функцию (например, два аргумента или числа в качестве аргументов), если хотите.источник
function maxnum {
наmaxnum() {
и это будет работать для гораздо большего количества оболочек.Из сценария оболочки можно использовать любой открытый статический метод Java (например, Math.min () ). Из bash на Linux:
Для этого требуется Java Shell Bridge https://sourceforge.net/projects/jsbridge/
Очень быстро, потому что вызовы методов внутренне переданы ; процесс не требуется.
источник
Большинство людей просто делают
sort -n input | head -n1
(или хвост), этого достаточно для большинства сценариев. Тем не менее, это немного неуклюже, если у вас есть цифры в строке вместо столбца - вы должны распечатать их в правильном формате (tr ' ' '\n'
или что-то подобное).Оболочки не совсем идеальны для числовой обработки, но вы легко можете просто вставить какую-нибудь другую программу, которая лучше в ней. В зависимости от ваших собственных предпочтений, вы максимально коллируете
dc
(немного запутанно, но если вы знаете, что делаете, это нормально - смотрите ответ mikeserv), илиawk 'NR==1{max=$1} {if($1>max){max=$1}} END { print max }'
. Или, возможно,perl
или,python
если вы предпочитаете. Одним из решений (если вы хотите установить и использовать менее известное программное обеспечение) было быised
(особенно если ваши данные находятся в одной строке: вам просто нужно это сделатьised --l input.dat 'max$1'
).Поскольку вы запрашиваете два числа, это все излишне. Этого должно быть достаточно:
источник
sys.argv
:python2 -c 'import sys; print (max(sys.argv))' "$@"
sort + head
излишни, ноpython
не являются, не вычисляются.python
потому что он аккуратный.python
фанатик (или потому, что он не требует форка и дополнительного гигантского интерпретатора) . Или, может быть, оба.