Существует ли команда Unix, которая дает минимум/максимум двух чисел?

Поскольку Монетным двором является полученный Debian, самый легкий путь состоит в том, чтобы обновить Ваш sources.list для использования новой версии репозиториев затем используйте склонный - добираются (или способность) для установки debconf, и склонный - добираются (и/или способность). Затем dist-обновление.

Не будучи пользователем Монетного двора самостоятельно, я не знаю что корректное sources.list должен быть (и 5 секунд на Google не показали его), и я, очевидно, не протестировал это. Но будучи долгим временем пользователь Debian это, довольно вероятно, будет безопасно. Даже все еще тест это самостоятельно прежде на самом деле сделать это и имеет заднюю часть Ваших данных.

39
05.08.2019, 21:05
11 ответов

Вы можете сравнить только два числа с dc , например:

dc -e "[$1]sM $2d $1<Mp"

... где "$ 1" - ваше максимальное значение, а «$ 2» - это число, которое вы должны вывести, если оно меньше «$ 1» . Для этого также требуется GNU dc - но вы можете сделать то же самое с переносом, например:

dc <<MAX
    [$1]sM $2d $1<Mp
MAX

В обоих вышеупомянутых случаях вы можете установить точность, отличную от 0 (по умолчанию) как $ {desire_precision} k . Для обоих также необходимо убедиться, что оба значения являются определенно числами , потому что dc может вызывать system () с ! оператор.

С помощью следующего небольшого скрипта (и следующего) вы также должны проверить ввод - например, grep -v \! | Dc или что-то еще для надежной обработки произвольного ввода. Вы также должны знать, что dc интерпретирует отрицательные числа с префиксом _ , а не с префиксом - , потому что последний является оператором вычитания.

Кроме того, с помощью этого сценария dc будет читать столько последовательных \ n чисел, разделенных ewline, сколько вы хотели бы указать, и печатать для каждого из ваших ] $ max значение или вход, в зависимости от того, что меньше из двух:

dc -e "${max}sm
       [ z 0=? d lm<M p s0 lTx ]ST
       [ ? z 0!=T q ]S?
       [ s0 lm ]SM lTx"

Итак ...каждый из этих [ в квадратных скобках ] пространств представляет собой объект dc string , который S отнесен к каждому соответствующему массиву - любой из T , ? или M . Помимо некоторых других вещей, которые dc может делать со строкой , он также может e x выполнять ее как макрос. Если все устроить правильно, то достаточно просто собрать полноценный маленький dc скрипт.

dc работает в стеке . Все входные объекты складываются каждый после последнего - каждый новый входной объект толкает последний верхний объект и все объекты под ним вниз в стеке по одному по мере добавления. Большинство ссылок на объект относятся к верхнему значению стека, а большинство ссылок выталкивают эту верхнюю часть стека (которая вытягивает все объекты ниже на один) .

Помимо основного стека, существует также (как минимум) 256 массивов, и каждый элемент массива имеет свой собственный стек. Я здесь особо не использую. Я просто сохраняю строки, как упомянуто, так что я могу l загружать их, когда нужно, и e x выполнять их условно, и я s разорвал $ max в верхней части массива m .

В любом случае, этот небольшой фрагмент dc в основном выполняет то же самое, что и ваш сценарий оболочки. Он действительно использует опцию GNU-ism -e - поскольку dc обычно берет свои параметры из стандартного входа - но вы можете сделать то же самое, например:

echo "$script" | cat - /dev/tty | dc

... if $ script выглядел как приведенный выше бит.

Это работает следующим образом:

  • lTx - Это l oads и e x запускает макрос, хранящийся в верхней части T (для test, я полагаю - я обычно выбираю эти имена произвольно) .
  • z 0 =? - T est затем проверяет глубину стека w / z и, если стек пуст, (чтение: содержит 0 объектов) вызывает макрос ? .
  • ? z0! = T q - Макрос ? назван в честь встроенной команды ? dc , которая считывает строку ввода из стандартного ввода, но я также добавил еще один z проверка глубины стека для него, чтобы он мог q использовать всю маленькую программу, если она вытягивает пустую строку или достигает EOF. Но если это так ! нет, и вместо этого успешно заполняет стек, он снова вызывает T est.
  • d lm - T est затем d создаст верхнюю часть стека и сравнит ее с $ max (как хранится в м ) . Если m - меньшее значение, dc вызывает макрос M .
  • s0 lm - M просто выталкивает вершину стека и выгружает ее в фиктивный скаляр 0 - просто дешевый способ выталкивания стека. Он также l загружает m снова, прежде чем вернуться к T est.
  • p - это означает, что если m меньше текущей вершины стека, то m заменяет его ( d в любом случае его повторное использование) и здесь p ритировано, в противном случае это не так, и независимо от того, что было введено, вместо этого рисуется p .
  • s0 - После (поскольку p не выталкивает стек) мы снова сбрасываем верх стека в 0 , а затем. ..
  • lTx -рекурсивно l загрузить T еще раз, затем e 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.

20
27.01.2020, 19:35

Вы можете определить функцию как

maxnum(){
    if [ $2 -gt $1 ]
    then
        echo $2
    else
        echo $1
    fi
}

называть его как Maxnum 54 42 и его эхо 54 . Вы можете добавить информацию проверки внутри функции (например, два аргумента или номера в качестве аргументов), если вам нравится.

4
27.01.2020, 19:35

Вы можете определить библиотеку предопределенных математических функций для BC , а затем используйте их в командной строке.

Например, включите следующее в текстовом файле, таком как ~ / myextensions.bc :

define max(a,b){
  if(a>b)
  { 
   return(a)
  }else{
   return(b)
  }
}

Теперь вы можете вызвать BC :

> echo 'max(60,54)' | bc ~/MyExtensions.bc
60

FYI, есть Функции бесплатной математики такие как это , доступны в Интернете.

Используя этот файл, вы можете легко рассчитать более сложные функции, такие как GCD :

> echo 'gcd (60,54)' | bc ~/extensions.bc -l
6
6
27.01.2020, 19:35

сортировка и головка могут сделать это:

numbers=(1 4 3 5 7 1 10 21 8)
printf "%d\n" "${numbers[@]}" | sort -rn | head -1       # => 21
24
27.01.2020, 19:35

Большинство людей просто бы сделали сортировку -n ввод | головой -n1 (или хвостом), этого достаточно для большинства сценарных ситуаций. Однако, это немного неуклюже, если у вас есть цифры в строке, а не в колонке - вы должны распечатать его в правильном формате (tr '' '\n' или что-то подобное).

Оболочки не совсем идеальны для числовой обработки, но Вы легко можете просто подключиться к какой-нибудь другой программе, которая в ней лучше. В зависимости от ваших собственных предпочтений, вы можете максимально вызывать dc (слегка затруднительно, но если вы знаете, что делаете, все в порядке - смотрите ответ mikeserv), или awk 'NR==1{max=$1}. {if($1>max){max=$1}} END {печать максимум}'. Или, возможно, perl или python, если хотите. Одним из решений (если вы хотите установить и использовать менее известное программное обеспечение) будет ised (особенно если ваши данные находятся в одной строке: вам нужно просто сделать ised --l input.dat 'max$1').


Так как Вы просите два числа, это все перебор. Этого должно быть достаточно:

python -c "print(max($j,$k))"
0
27.01.2020, 19:35

Чтобы получить большее значение $ a and $ b Используйте это:

[ "$a" -gt "$b" ] && $a || $b

, но вам нужно что-то вокруг, вы, вероятно, не хотите выполнить номер, поэтому для отображения большего значения двух используемых «Echo» «

[ "$a" -gt "$b" ] && echo $a || echo $b

Вышеприведенное хорошо вписывается в функцию оболочки, например,

max() {
   [ "$1" -gt "$2" ] && echo $1 || echo $2
}

, чтобы назначить большее количество двумя для переменной, используйте эту модифицированную версию:

[ "$a" -gt "$b" ] && biggest=$a || biggest=$b

или использовать определенную функцию:

biggest=$( max $a $b )

Вариант функции также дает вам. Возможность добавить входную ошибку, проверку аккуратно.

Чтобы вернуть максимум двух номеров десятичных / плавающих точек, которые вы можете использовать awk

decimalmax() { 
   echo $1 $2 | awk '{if ($1 > $2) {print $1} else {print $2}}'; 
}

Редактировать: Использование этой техники Вы можете создать функцию «ограничения», которая работает на другую сторону согласно вашим редактированию / примечанию. Эта функция вернет нижнюю часть двух, например:

limit() {
   [ "$1" -gt "$2" ] && echo $2 || echo $1
}

Мне нравится ставить утилиты в отдельный файл, вызовите его MyProgram.funcs и используйте его в скрипте, как следует следующие:

#!/bin/bash

# Initialization. Read in the utility functions
. ./myprogram.funcs

# Do stuff here
#
[ -z "$1" ] && { echo "Needs a limit as first argument." >&2; exit 1; }

read number
echo $( limit $1 $number )

FWIW Это все еще делает то, что вы сделали, и ваша версия, даже если она более Verbose, так же эффективна.

Более компактная форма не совсем лучше, но предотвращает беспорядок в ваших сценариях. Если у вас есть много простых, если бы и другие сконструированы, скрипт быстро расширяется.

Если вы хотите повторно использовать проверку на более крупные / меньшие номера несколько раз в одном сценарии, поставьте его в функцию. Функциональный формат облегчает отладку и повторное использование и позволяет легко заменить эту часть сценария, например, с помощью команды awk, чтобы иметь возможность обрабатывать нецеловые десятичные числа.

Если это один случай для использования, просто код его в режиме онлайн.

4
27.01.2020, 19:35

Слишком долго для комментария:

Хотя вы можете делать эти вещи, например, с помощью сортировки | head или сортировки | tail combos, это кажется довольно неоптимальным как с точки зрения ресурсов, так и с точки зрения обработки ошибок. Что касается выполнения, комбо означает порождение 2 процессов только для того, чтобы проверить две строки. Это, кажется, немного чересчур.

Более серьезная проблема заключается в том, что в большинстве случаев необходимо знать, что вход является вменяемым, то есть содержит только числа. @решениеglennjackmann ловко решает эту проблему, так как printf %d должен блевать на не входе. Оно не будет работать и с флотами (если только вы не измените спецификатор формата на %f, где вы столкнетесь с проблемами округления).

test $1 -gt $2 даст вам указание на то, что сравнение прошло неудачно или нет (статус выхода 2 означает, что во время теста произошла ошибка. Так как обычно это встроенная оболочка, то дополнительного процесса не порождается - речь идет о порядке исполнения в сотни раз быстрее. Но работает только с целыми числами.

Если вам случайно понадобится сравнить пару чисел с плавающей точкой, то интересным вариантом может быть bc:

define x(a, b) {
    if (a > b) {
       return (a);
    }
    return (b);
 }

будет эквивалент test $1 -gt $2, а использование в оболочке:

max () { printf '
    define x(a, b) {
        if (a > b) {
           return (a);
        }
        return (b);
     }
     x(%s, %s)
    ' $1 $2 | bc -l
}

все еще почти в 2.5 раза быстрее, чем printf | сортировка | head (для двух чисел).

Если вы можете полагаться на расширения GNU в bc, то вы можете также использовать функцию read() для считывания чисел непосредственно в сценарии bc.

5
27.01.2020, 19:35

Если вы знаете вы имеете дело с двумя целыми числами a и b , то этих простых арифметических разложений оболочки с использованием тернарного оператора достаточно, чтобы получить числовое значение max:

$(( a > b ? a : b ))

и числовой минимум:

$(( a < b ? a : b ))

Например

$ a=10
$ b=20
$ max=$(( a > b ? a : b ))
$ min=$(( a < b ? a : b ))
$ echo $max
20
$ echo $min
10
$ a=30
$ max=$(( a > b ? a : b ))
$ min=$(( a < b ? a : b ))
$ echo $max
30
$ echo $min
20
$ 

Вот сценарий оболочки, демонстрирующий это:

#!/usr/bin/env bash
[ -z "$1" ] && { echo "Needs a limit as first argument." >&2; exit 1; }
read number
echo Min: $(( $number  < $1 ? $number : $1 ))
echo Max: $(( $number  > $1 ? $number : $1 ))
89
27.01.2020, 19:35

Desde un script de shell, hay una forma de usar cualquier método estático público de Java (y, por ejemplo, Math.min()). Desde bash en Linux:

. jsbInit
jsbStart 
A=2 
B=3 
C=$(jsb Math.min "$A" "$B")
echo "$C"

Esto requiere Java Shell Bridgehttps://sourceforge.net/projects/jsbridge/

Muy rápido, porque las llamadas a métodos se canalizan internamente ; no se requiere ningún proceso.

2
27.01.2020, 19:35

Цитата из вопроса ОП, выделение мое:

I was wondering if there was not a standard command for this

По моему мнению, в большинстве ответов отсутствует точка зрения ОП, поскольку все они представляют собой настраиваемые сценарии, а не стандартные решения. Вот два решения с использованием инструментов, специально предназначенных для этой работы. Обычно эти инструменты предварительно -не устанавливаются.

Общее решение для списка из (возможных чисел с плавающей точкой ), по одному в строке

Онемение из Нума -Утилс

Для получения минимального использования yourCommand | numbound -l.
-l(нижний регистр L )означает нижняя граница .

В Debian и Ubuntu numboundустанавливается с помощью apt install num-utils. В этот пакет также входят аналогичные инструменты для усреднения чисел, их суммирования и так далее. Описание пакета в apt show num-utilsперечисляет их все :

.

numaverage, numbound, numinterval, numnormalize, numgrep, numprocess, numsum, numrandom, numrange,numround

Датамаш GNU

Для получения минимального использования yourCommand | datamash min 1.
1(единица )обозначает первый столбец во входных данных.

В Debian и Ubuntu datamashустанавливается с помощью apt install datamash. Этот инструмент может делать гораздо больше, см. примеры и полное руководство .

2
29.04.2020, 07:27

Учитывая высокую портативность и плотность, учтите, чтоexpr-он стал моим швейцарским армейским ножом для испытаний, которые в противном случае потребовали бы echoполучения результата и, таким образом, стали бы громоздкими.

expr $a \& $a \> $b \| $b 

Печатает большее из двух чисел -переворачивает >на <и получает меньшее:)

Обратите внимание, что это не работает для отрицательных чисел.

0
04.11.2021, 09:03

Теги

Похожие вопросы