최소 / 최대 두 숫자를 제공하는 유닉스 명령이 있습니까?


37

에서 읽은 숫자를 제한하는 명령을 찾고있었습니다 stdin.

나는 그 목적을 위해 작은 스크립트를 작성했지만 (평판은 환영한다), 이것에 대한 표준 명령이 간단하고 일반적인 사용 사례가 아닌지 궁금했다.

최소 두 개의 숫자 를 찾는 내 스크립트 :

#!/bin/bash
# $1 limit

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

read number

if [ "$number" -gt "$1" ]; then
        echo "$1"
else
        echo "$number"
fi

답변:


20

다음과 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()w / 호출 !연산자.

다음의 작은 스크립트 (및 다음 스크립트 ) 를 사용하면 입력을 확인해야 grep -v \!|dc합니다. 임의의 입력을 강력하게 처리 할 수있는 것입니다. 또한 dc음수는 _접두어가 아닌 접두사로 해석 -합니다. 후자는 빼기 연산자이기 때문입니다.

그 외에도이 스크립트를 사용 dc하면 제공 할 수있는만큼 많은 연속 \newline으로 구분 된 숫자를 읽고 $maxwo 중 작은 값에 따라 값 또는 입력 각각에 대해 인쇄합니다 .

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있는 몇 가지 다른 것 외에도 매크로로 예리하게 만들 수 있습니다 . 제대로 배치하면 완벽하게 작동하는 작은 스크립트가 간단하게 조립됩니다.xdc

dc스택 에서 작동합니다 . 모든 입력 객체는 각각 마지막에 쌓입니다. 각각의 새로운 입력 객체는 마지막 상단 객체와 그 아래에있는 모든 객체가 추가 될 때마다 스택 아래로 아래로 밀립니다. 객체에 대한 대부분의 참조는 최상위 스택 값에 대한 것이며 대부분의 참조 는 스택의 최상위를 나타 냅니다 (아래에있는 모든 객체를 1 씩 끌어옵니다) .

메인 스택 외에도 (적어도) 256 개의 어레이가 있으며 각 어레이 요소에는 자체 스택이 제공됩니다. 나는 여기서 많이 사용하지 않습니다. 내가 할 수 있습니다 언급 한 바와 같이 그냥 문자열을 저장하기 l원하는 경우를 OAD 및 전자 x조건부 ecute을, 나는 s찢어 $max의 상단에서의 값을 m배열입니다.

어쨌든,이 작은 부분은 dc주로 쉘 스크립트가하는 일을 수행합니다. 일반적으로 표준 입력에서 매개 변수를 가져 오는 -e것처럼 GNU-ism 옵션을 사용 dc하지만 다음과 같이 수행 할 수 있습니다.

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

... $script위 비트처럼 보이면.

다음과 같이 작동합니다.

  • lTx-이것은 상단에 저장된 매크로를 l무효화하고 xecutes T (테스트를 위해, 나는 보통 그 이름을 임의로 선택합니다) .
  • z 0=?- T동부 표준시 다음 w 스택 깊이를 테스트 / z스택이 비어있는 경우, 그리고 (0 객체를 보유하고 읽기) 가 호출 ?매크로를.
  • ? z0!=T q- ?매크로는 ? dcstdin에서 입력 라인을 읽는 내장 명령의 이름을 따서 명명 되었지만, 또 다른 z스택 깊이 테스트를 추가 q하여 빈 줄을 가져 오거나 EOF에 도달하면 전체 작은 프로그램을 사용할 수 있습니다 . 그러나 !스택을 채우지 않고 대신 성공적으로 T채우면 est를 다시 호출 합니다.
  • d lm<M- TEST는 것이다 d스택의 상단과 uplicate과 비교 $max (에 저장된 m) . 경우 m적은 값이, dc부르는 M매크로를.
  • s0 lm- M스택의 상단을 팝하여 더미 스칼라에 덤프합니다 0-스택을 팝하는 저렴한 방법입니다. 또한 est 로 돌아 가기 전에 다시 l소리를냅니다 .mT
  • p- 경우에 것을이 수단 m스택의 현재 정상보다 적은 다음, m그것을 대체 합니다 ( d어쨌든, 그것의 uplicate)을 여기에있다 printed는 다른이와 어떤 입력이되어 있었다하지 않는 p대신 rinted.
  • s0-나중에 ( p스택을 팝하지 않기 때문에 ) 스택 상단을 0다시 덤프 한 다음 ...
  • lTx- 반복적으로 lOAD T추정 한 번 더 한 후 전자 xecute을 다시.

따라서이 작은 조각을 실행하고 대화식으로 터미널 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명령으로 먼저 설정하면 임의의 정밀도 부동 소수점을 처리 할 수 ​​있습니다 . 또한 input 또는 output radices를 독립적으로 변경할 수 있습니다. 때로는 예상치 못한 이유로 유용 할 수 있습니다. 예를 들면 다음과 같습니다.

echo 100000o 10p|dc
 00010

... 먼저 dc출력 기수를 100000으로 설정 한 다음 10을 인쇄합니다.


3
두 번 읽은 후 무슨 일이 있었는지 전혀 모르는 +1 이것에 대해 깊이 탐구하려면 시간이 걸릴 것입니다.
Minix

@Minix-meh-혼란 스러울 경우 가장 오래된 Unix 프로그래밍 언어를 탐구 할 필요가 없습니다. 어쩌면 dc발가락에 몇 개씩 물을 뿌릴 수도 있습니다.
mikeserv

1
@ mikeserv 너무 늦었다. 나는 미래 세대가 나를 조심스럽게 이야기하기를 바랍니다. 대괄호와 문자 사방 ...
Minix

@Minix-무슨 뜻인가요? 당신은 그것을 위해 갔다? 아주 좋은- dc변덕스러운 짐승이지만 모든 유닉스 시스템에서 가장 빠르고 이상하게 유능한 공통 유틸리티 일 수 있습니다. 쌍을 이루면 sed특별한 일을 할 수 있습니다. 나는 그것을 가지고 dd놀았고 최근에 나는 괴물 같은 괴물을 대체 할 수 있습니다 readline. 여기 내가하고있는 일 의 작은 샘플 이 있습니다. rev안으로 들어가는 dc것은 거의 어린이 놀이입니다.
mikeserv

1
@Minix-괄호로 조심하십시오. 문자열 안에 대괄호를 넣을 수있는 방법은 없습니다. 최선을 다하는 것입니다 [string]P91P93P[string]P. 그래서 나는 sed당신 에게이 작은 것을 유용하게 생각할 수 있습니다 : sed 's/[][]/]P93]&[1P[/g;s/[]3][]][[][1[]//g'항상 사각형을 문자열 닫는 대괄호로 바꾼 다음에 a P, 사각형의 10 진수 값 및 다른 값으로 바꿉니다 P. 그런 다음 열린 [대괄호를 사용하여 문자열을 계속하십시오. w / dc의 문자열 / 숫자 변환 기능을 망쳤다면 Dunno는 특히 od재미있게 결합 할 수 있습니다.
mikeserv

88

두 개의 정수 a와를 다루는 것을 알고 있다면 삼항 연산자를 사용하는b 간단한 쉘 산술 확장으로 숫자를 최대로 지정할 수 있습니다 .

$(( 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 ))

좋은 대답입니다. 마이너 모드 : "> ="에도 사용할 수 있습니까?
Sopalajo de Arrierez

@SopalajodeArrierez 나는 당신이 무슨 뜻인지 완전히 확신하지 못합니다. 당신은 또한 할 수 max=$(( a >= b ? a : b ))있지만 결과는 완전히 동일합니다-a와 b가 같으면 어떤 것이 반환되는지는 중요하지 않습니다. 그게 당신이 묻는 것입니까?
Digital Trauma

진심으로 감사합니다, DIgital Trauma. 부울 연산자 "> ="가 가능한지 궁금합니다.
Sopalajo de Arrierez

@SopalajodeArrierez- if (( a >= b )); then echo a is greater than or equal to b; fi그게 당신이 요구하는 것입니까? (사용주의 (( ))대신에 여기를 $(( )))
디지털 외상

아, 그래요 지금은 이해. 나는 쉘 확장에 대해 많이 모른다. 그래서 나는 보통 조건들 사이에서 혼란스러워한다. 다시 감사합니다.
Sopalajo de Arrierez

25

sort그리고 head이것을 할 수 있습니다 :

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

2
이 유의 O(n log(n))최대의 효율적인 구현이 될 것입니다 동안 O(n). 그러나 n=2두 프로세스의 생성이 훨씬 더 큰 오버 헤드이기 때문에 우리의 중요성은 적습니다 .
Lie Ryan

1
@ glenn-jackman은 사실이지만 질문이 문제인지 확실하지 않습니다. 가장 효율적인 방법은 없었습니다. 나는 질문이 편의성에 관한 것이라고 생각합니다.
David Hoelzer

1
@DavidHoelzer-여기에 제공된 답변 중에서도이 작업을 수행하는 가장 효율적인 방법은 아닙니다. 숫자 세트로 작업하는 경우 여기보다 더 효율적인 적어도 하나의 다른 대답이 있으며 (자릿수로) 두 정수로 작업하는 경우 다른 것보다 더 효율적입니다 (크기 순서로) . 그래도 편리하지만 (개인적으로 쉘 배열을 생략 할 것입니다) .
mikeserv

1
다음과 같이 어레이없이 수행 할 수 있습니다.numbers="1 4 3 5 7 1 10 21 8"; echo $numbers | tr ' ' "\n" | sort -rn | head -n 1
ngreen

1
보다 효율적인 접근 방식은 다음과 같습니다.max=0; for x in $numbers ; do test $x -gt $max && max=$x ; done
ngreen

6

미리 정의 된 수학 함수 라이브러리를 정의한 bc다음 명령 줄에서 사용할 수 있습니다.

예를 들어, 다음과 같은 텍스트 파일에 다음을 포함하십시오 ~/MyExtensions.bc.

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

이제 다음으로 전화 할 수 있습니다 bc.

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

참고로, 온라인에서 사용할 수 있는 무료 수학 라이브러리 기능 있습니다.

이 파일을 사용하면 GCD다음 과 같은보다 복잡한 함수를 쉽게 계산할 수 있습니다 .

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

내가 실수하지 않으면, 그러한 함수는 필요한 경우 실행 파일로 컴파일 할 수도 있습니다. 비록 GNU 가 더 이상 그렇지 않다고 해도 (그러나 GNU 와 GNU 는 엄청난 양의 코드베이스를 공유 하지만) 대부분 bc은 오늘날의 dc프론트 엔드 라고 생각 합니다. 어쨌든, 이것이 가장 좋은 대답 일 것입니다. bcdcbc
mikeserv

쉘 스크립트 파일 내에서 이것을 편리하게 호출 bc하기 위해 함수 호출 직전에 함수 정의도 파이프 할 수 있습니다 . 아니 두 번째 파일이 없습니다 다음 필요 :
tanius

5

댓글이 너무 깁니다 :

예를 들어 sort | head또는 sort | tail콤보로 이러한 작업을 수행 할 수 있지만 리소스 및 오류 처리 측면에서 다소 차선적인 것 같습니다. 실행과 관련하여 콤보는 두 줄을 확인하기 위해 두 개의 프로세스를 생성하는 것을 의미합니다. 약간 과잉 인 것 같습니다.

더 심각한 문제는 대부분의 경우 입력이 제정신이며 숫자 만 포함한다는 사실을 알아야합니다. @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쉘에서 in을 사용 하는 것과 같습니다 .

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

여전히 printf | sort | head두 숫자 보다 거의 2.5 배 빠릅니다 .

에서 GNU 확장을 사용할 수 있다면이 함수를 bc사용 read()하여 숫자를 bcsript 로 직접 읽을 수도 있습니다 .


내 생각은 정확히 - 난 그냥이 밖으로 다림질되었다,하지만 당신은 그것에 나를 이길 : dc -e "${max}sm[z0=?dlm<Mps0lTx]ST[?z0!=Tq]S?[s0lm]SMlTx"- 오, 그건 제외하고 dc모든 일을 (에코 제외하고는 할 수 있지만) - 그것은 인쇄 중 및 stdin을 읽 $max거나 따라 입력 된 숫자를하는에 더 작습니다. 어쨌든, 나는 그것을 설명하는 데 정말로 신경 쓰지 않으며 대답은 내가 쓰는 것보다 낫습니다. 제발 투표 해주세요
mikeserv

@mikeserv는 실제로 설명 dc스크립트 를 갖는 것이 정말 좋을 것입니다. 요즘 RPN은 종종 보이지 않습니다.
peterph

역 폴란드 표기법 (일명 Postfix 표기법). 또한 dc자체적으로 I / O를 수행 할 수있는 경우보다 훨씬 우아합니다.
peterph

4

$ a 및 $ b의 더 큰 값을 얻으려면 다음을 사용하십시오.

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

그러나 그 주위에 무언가가 필요합니다. 아마도 숫자를 실행한다는 의미는 아니므로 두 가지 사용 "에코"의 더 큰 값을 표시하려면

[ "$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 이것은 여전히 ​​당신이 한 일을하고 있으며, 더 장황하지만 버전은 효율적입니다.

더 컴팩트 한 형태는 실제로는 좋지 않지만 스크립트에서 혼란을 방지합니다. 간단한 if-then-else-fi 구문이 많은 경우 스크립트가 빠르게 확장됩니다.

하나의 스크립트에서 더 크거나 작은 수의 검사를 여러 번 다시 사용하려면 함수에 넣으십시오. 함수 형식을 사용하면 디버그 및 재사용이 쉬워지고 정수가 아닌 10 진수를 처리 할 수있는 awk 명령과 같이 스크립트의 해당 부분을 쉽게 바꿀 수 있습니다.

단일 사용 사례 인 경우 인라인으로 코딩하면됩니다.


4

함수를 다음과 같이 정의 할 수 있습니다

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

로 호출하면 maxnum 54 42에코 54됩니다. 원하는 경우 함수 내에 유효성 검사 정보 (예 : 두 개의 인수 또는 숫자를 인수로 추가)를 추가 할 수 있습니다.


대부분의 쉘은 부동 소수점 산술을하지 않습니다. 그러나 정수에는 효과가 있습니다.
오리온

1
이 기능은 불필요하게 POSIX와 호환되지 않습니다. 로 변경 function maxnum {하면 maxnum() {훨씬 더 많은 셸에서 작동합니다.
Charles Duffy

2

쉘 스크립트에서 사용하는 방법이 어떤 자바 공공 정적 방법 (그리고 예를 들어 Math.min을 () ). Linux의 bash에서 :

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

여기에는 Java Shell Bridge 가 필요합니다 https://sourceforge.net/projects/jsbridge/

메소드 호출이 내부적으로 파이프 되기 때문에 매우 빠릅니다 . 프로세스가 필요하지 않습니다.


0

대부분의 사람들은 단지 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').


두 개의 숫자를 요구하기 때문에 이것은 모두 과잉입니다. 이것으로 충분합니다 :

python -c "print(max($j,$k))"

1
다음을 사용하면 더 나을 수 있습니다 sys.argv.python2 -c 'import sys; print (max(sys.argv))' "$@"
muru

1
sort + head과도하지만 python계산되지 않은 인수 .
mikeserv

라인 위의 모든 메소드는 거대한 숫자 세트를 처리하고 파이프 또는 파일에서 읽는 이러한 종류의 사용을 명시 적으로 제안하도록 설계되었습니다. 2 개의 인수에 대한 최소 / 최대는 다르게 느끼는 질문입니다. 스트림 대신 함수를 호출합니다. 방금 스트림 접근 방식이 과도하다는 것을 의미했습니다. 사용하는 도구는 임의적입니다. 단지 python깔끔하기 때문에 사용 했습니다.
오리온

나는 부를 것이다 이 제안 솔루션 깔끔한을 하지만 내가이기 때문에 수 있습니다 python옹졸한을 (그것은 포크와 추가 거대한 통역을 필요로하지 않기 때문에 또는) . 아니면 둘 다.
mikeserv

@ mikeserv 나는 그들이 정수라는 것을 알고 있다면 그것을 사용할 것입니다. 내가 언급 한 모든 솔루션은 숫자가 실수 일 수 있다고 가정합니다 .bash는 부동 소수점을 수행하지 않으며 zsh가 기본 쉘이 아닌 경우 포크 (및 나이프) 필요합니다.
오리온
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.